Skip to content

Instantly share code, notes, and snippets.

@punchagan
Created June 20, 2014 21:17
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save punchagan/76e8771fc26cd243f3ac to your computer and use it in GitHub Desktop.
Save punchagan/76e8771fc26cd243f3ac to your computer and use it in GitHub Desktop.
An example script to understand how OAuth2 works
""" An example script to understand how OAuth2 works. """
from requests import get, post, Session
#### Credentials of the resource owner on the auth server
username = ''
password = ''
#### Credentials/info of the client on the auth server
client_id = ''
client_secret = ''
# The redirect url should match exactly with the url provided when
# registering the client, if one was provided.
# This URI is a special one, which prevents any redirects and puts the
# authorization code, directly in the URI. This is only being used
# for demonstation purposes.
REDIRECT_URI = 'urn:ietf:wg:oauth:2.0:oob'
#### Auth server end-points
AUTHORIZE_URL='https://www.hackerschool.com/oauth/authorize'
ACCESS_TOKEN_URL='https://www.hackerschool.com/oauth/token'
#### Resource server end-points
TEST_URL = 'https://www.hackerschool.com/api/v1/people/me'
###############################################################################
def oauth_flow():
""" The protocol flow.
+----------+
| Resource |
| Owner |
| |
+----------+
^
|
(B)
+----|-----+ Client Identifier +---------------+
| -+----(A)-- & Redirection URI ---->| |
| User- | | Authorization |
| Agent -+----(B)-- User authenticates --->| Server |
| | | |
| -+----(C)-- Authorization Code ---<| |
+-|----|---+ +---------------+
| | ^ v
(A) (C) | |
| | | |
^ v | |
+---------+ | |
| |>---(D)-- Authorization Code ---------' |
| Client | & Redirection URI |
| | |
| |<---(E)----- Access Token -------------------'
+---------+ (w/ Optional Refresh Token)
Note: The lines illustrating steps (A), (B), and (C) are broken into
two parts as they pass through the user-agent.
"""
# Create a User-Agent (session object emulates the browser)
session = Session()
# Client requests authorization grant: Sends client_id and
# redirect_uri to the authorization server. (Step A)
request_authorization_grant(session)
# The authorization asks the user to authenticate, and then to
# authorize the client. Once, the resource owner authorizes the
# client, the user-agent is redirected to a url with the
# authorization code as a query parameter in the url. (See
# comment for REDIRECT_URI) (Step B)
authenticate(session, username, password)
# The user-agent gets redirected to the REDIRECT_URI specified by
# the client, and communicates the 'authentication_code' provided
# by the Authorization server. (Step B, C)
code_url = authorize_client(session).url
code = _get_code(code_url)
# The client can then use the authorization code to request an
# access token. The server may, optionally, return a refersh
# token along with the access token. (Step D, E)
access_token, refresh_token = request_access_token(code)
# The access token can be used to fetch the protected data. The
# refresh token can be used to renew the access token in case it
# expires.
protected_data = request_protected_resource(access_token)
return protected_data
###############################################################################
def authenticate(session, username, password):
""" Resource owner authenticates. """
data = {'email': username, 'password': password}
session.post('https://www.hackerschool.com/sessions', data=data)
def authorize_client(session):
""" Emulates the resource owner authorizing the client.
This function is essentially clicking on the "authorize" button
shown on the familiar "do you want to allow bogus-application to
use your hackerschool data?" page.
"""
data = {
'client_id': client_id,
'response_type': 'code',
'redirect_uri': REDIRECT_URI,
}
return session.post(AUTHORIZE_URL, data=data)
def request_access_token(code):
""" Client requests an access token using an authorization code.
'grant_type', 'code', 'redirect_uri', 'client_id' and
'client_secret' (if one was provided during registration) are all
required parameters.
"""
data = {
'grant_type': 'authorization_code',
'code': code,
'redirect_uri': REDIRECT_URI
}
response_data = post(
ACCESS_TOKEN_URL, data=data, auth=(client_id, client_secret)
).json()
return response_data['access_token'], response_data['refresh_token']
def request_authorization_grant(session):
""" Client requests for authorization.
NOTE: The 'client_id' and 'response_type' are required arguments,
and the 'redirect_uri' is required, if it was speicified when the
client registered with the server. Also, to use this workflow the
'response_type' MUST be 'code'.
"""
data = {
'client_id': client_id,
'response_type': 'code',
'redirect_uri': REDIRECT_URI
}
return session.get(AUTHORIZE_URL, data=data)
def request_protected_resource(access_token, resource=TEST_URL):
""" Client requests a protected resource. """
headers = {'Authorization': 'Bearer %s' % access_token}
return get(resource, headers=headers).json()
def _get_code(url):
""" A client-internal method to get the authentication code.
Ideally, on user autorization, the user is redirected to a client
url, where the client can obtain the code.
In this example we cheat and call the method directly with the
url.
"""
_, code = url.rsplit('/', 1)
return code
if __name__ == "__main__":
print oauth_flow()
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment