-
-
Save punchagan/76e8771fc26cd243f3ac to your computer and use it in GitHub Desktop.
An example script to understand how OAuth2 works
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
""" 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