OAuth2 in Python

Last updated May 28th, 2021

In this article, we'll first look at what OAuth is. Then, we'll use the OAuthLib and Requests libraries to implement OAuth2.

Contents

Objectives

By the end of this article, you will be able to:

  1. Explain what OAuth and OAuth2 are and how they can be used
  2. Describe the OAuth2 flow between a web client and server
  3. Implement OAuth2 via the Web Application Flow (also known as the Authorization Code Grant)

What is OAuth?

OAuth is a secure open protocol for authorizing users between unrelated services. Put another way, it enables one service to access resources hosted on other services without having to share user credentials, like username and password.

It's all about delegation:

  1. One service (client) accesses resources from another service (resource server) on behalf of a user.
  2. The user does not have to share their credentials with the client.

Parties involved:

  1. Resource owner / user - the person who gives permission to access their protected resources hosted by a third-party provider
  2. Client - the web application acting on behalf of the user to access their resources hosted by a third-party provider
  3. Authorization server - the third-party server contacted by the client that displays a prompt for the user to authorize the client to act on the user's behalf
  4. Resource server - the third-party server hosting the user's protected resources

The authorization server and resource server may be the same entity.

OAuth2 is the latest version of the OAuth protocol used by services like Google, Spotify, Trello, and Vimeo, to name a few.

OAuth2 Web Application Flow

The OAuth2 protocol can be used in different types of applications, but it's most commonly used in web, mobile, and desktop applications. This section will address the deployment of OAuth2 in a web application, also known as the Web Application Flow (or Authorization Code Grant).

A simplified Web Application Flow is illustrated in this diagram:

Simplified Web Application Flow

The flow is basically a communication and exchange of information between a client (the web application) and a server (the OAuth2 provider), and it consists of three steps:

  1. Authorize
  2. Fetch access token
  3. Obtain user info

Before this flow can be implemented, a web developer typically has to register their web application with an OAuth2 provider and supply the following information:

  • Name of the application
  • Where the application is hosted
  • A URI endpoint (also known as the redirect URI or callback URL)

Once registered, the OAuth2 provider will provide the registrant with this information:

  • Client ID - a public credential to uniquely identify the web application, similar to a username
  • Client secret - a private credential to pass along to the server, similar to a password
  • Authorization server URL - a URL for the client to request authorization
  • Access token URL - a URL for the client to exchange an authorization code for an access token
  • Resource server URL - a URL for the client to access protected resources with an access token, which could also be the same as the authorization server

We'll now look at the three steps involved in the Web Application Flow in more depth.

Note that the term "client" will be used interchangeably with "web application".

Step 1: Authorize

The first step, authorize, is typically invoked at the beginning of the login process. In this step, the web application requests permission from the user to authorize access to their account hosted at a third-party OAuth2 provider.

Client - request permission

To start, the web application constructs a URL with the following information:

  • Response Type - tells the authorization server which flow or grant to use (use code for the Web Application Flow)
  • Client ID - identifies the web application
  • Redirect URI - where to redirect the user back to
  • Scope - specifies which portion(s) of the user profile the web application wishes to access
  • State - is a randomly-generated string that the web application provides, which the authorization server will simply pass back so that the web application can then validate to mitigate fraud

Here's a sample URL:

https://api.authorization-server.com/authorize
  ?response_type=code
  &client_id=123
  &redirect_uri=https://your-web-app.com/redirect
  &scope=photos
  &state=1234-zyxa-9134-wpst

The user is then redirected to that URL, and the authorization server will present them with a prompt asking if they would like to authorize this application’s request:

Authorization Dialog

Authorization Server - redirect back

After the user authorizes the web application to access their third-party account, the authorization server will redirect the user back to the web application via the redirect URL with the following information:

  • Code - a short-lived authorization code that the web application expects from the server
  • State - the state credential passed earlier from the client

Here's a sample redirect URL:

https://your-web-app.com/redirect
  ?code=123456
  &state=1234-zyxa-9134-wpst

In this step, the web application should verify that the state value matches the one it sends before to the authorization server. Doing this will help prevent any malicious attempts from hackers and CSRF attacks.

Step 2: Fetch Access Token

The second step is to exchange the authorization code for an access token.

Client - exchange

The web application sends an HTTP POST request to the authorization server's token endpoint with the following:

  • Grant Type - tells the authorization server, again, which flow or grant to use (use authorization_code for the Web Application Flow)
  • Code - the authorization code received by the web application from the authorization server
  • Redirect URI - where to redirect the user back to
  • Client ID - the same client identifier used in the authorization step
  • Client Secret - the password equivalent provided by the OAuth2 provider during registration

Here's a sample request URL:

https://api.authorization-server.com/token
  grant_type=authorization_code
  &code=123456
  &redirect_uri=https://your-web-app.com/redirect
  &client_id=123
  &client_secret=456

Authorization Server - grant token

The token endpoint will verify all the parameters in the request, ensuring that the code hasn’t expired and that the client ID and secret match. If everything checks out, it will generate an access token and return it in the response!

Assuming the authorization code is valid, the authorization server will generate an access token and return it back to the client.

For example:

{
  "access_token": "KtsgPkCR7Y9b8F3fHo8MKg83ECKbJq31clcB",
  "expires_in": 3600,
  "token_type": "bearer"
}

Additional properties (like scope and refresh_token) may be returned in the response depending on the OAuth2 provider.

Step 3: Obtain User Info

Finally, the web application can use the access token to access protected resources on behalf of the user.

Client - request resources

The web application typically sends an HTTP GET request to the resource server with the following credentials with the access token in the HTTP Authorization header.

For example:

GET /user HTTP/1.1
Host: api.resource-server.com
Authorization: Bearer access_token

The header type (Bearer in the above example) varies depending on the OAuth2 provider.

Resource Server - send resources

The resource server, which is sometimes the same as the authorization server, validates the access token. If valid, the resource server sends the requested data back.

For example:

{
   "name": "Aaron Smith",
   "bio": "Software Engineer",
   "avatar_url": "http://api.resource-server.com/image/aaron_smith"
}

Implementation

OAuthLib is a popular Python framework that implements generic, specification-compliant and comprehensive interfaces to OAuth1 and OAuth2. Requests is a popular Python HTTP library that makes sending HTTP/1.1 requests rather straightforward. Together, they can be used to implement the OAuth2 Web Application Flow.

Step 1: Authorize

OAuthLib provides a WebApplicationClient class that implements the Web Application Flow described above. After you register with an OAuth2 provider and obtain a client ID, create a new instance of WebApplicationClient in the web application.

For example:

from oauthlib.oauth2 import WebApplicationClient

client_id = 'xxxxx'
client = WebApplicationClient(client_id)

To facilitate the authorization step in the Web Application Flow, the WebApplicationClient class provides a prepare_request_uri() method that takes an authorization server URL and its corresponding credentials to form a complete URL.

For example:

authorization_url = 'https://api.authorization-server.com/authorize'

url = client.prepare_request_uri(
  authorization_url,
  redirect_uri = 'https://your-web-app.com/redirect',
  scope = ['read:user'],
  state = 'D8VAo311AAl_49LAtM51HA'
)

When printed, url will return:

https://api.authorization-server.com/authorize
  ?response_type=code
  &client_id=xxxxx
  &redirect_uri=https://your-web-app.com/redirect
  &scope=read:user
  &state=D8VAo311AAl_49LAtM51HA

The web application can redirect the user to this URL. At this point, the authorization server will present a prompt, asking the user to authorize the request.

Step 2: Fetch Access Token

Again, in this step, after the user approves the request, they are redirected back to the client with a response containing an authorization code and state.

After extracting and validating the accuracy of the state value, the web application can utilize the WebApplicationClient's prepare_request_body() method to construct the URL needed to fetch an access token from the authorization server.

For example:

data = client.prepare_request_body(
  code = 'yyyyyyy',
  redirect_uri = 'https://your-web-app.com/redirect',
  client_id = 'xxxxx',
  client_secret = 'zzzzzzz'
)

When printed, data will return:

grant_type=authorization_code
  &client_id=xxxxx
  &client_secret=zzzzzzz
  &code=yyyyyyy
  &redirect_uri=https//your-web-app.com/redirect

Notice that the key-value pair of grant_type=authorization_code is conveniently pre-pended by prepare_request_body().

At this point, we can utilize the Requests library to send an HTTP POST request to the token URL provided by the OAuth2 provider.

For example:

token_url = 'https://api.authorization-server.com/token'
response = requests.post(token_url, data=data)

OAuthLib's WebApplicationClient class also provides a parse_request_body_response() method to help us manage the response data as a Python dictionary. For example, we can pass response.text to this method, which will save the dictionary in client.token:

client.parse_request_body_response(response.text)

The value of client.token might look something like this:

{
   'access_token': 'KtsgPkCR7Y9b8F3fHo8MKg83ECKbJq31clcB',
   'scope': ['read:user'],
   'expires_at': 1619473575.641959,
   'expires_in': 3599,
   'token_type': 'bearer'
}

Step 3: Obtain User Info

The last step in the Web Application Flow is to retrieve the desired protected resource from the resource server. We'll need to prepare an HTTP Authorization header with the correct type and value. Depending on the implementation of the OAuth2 provider, the authorization header type could be Token or Bearer. We can use the get() method from the Requests library to send an HTTP GET request to the resource server with the correctly-formatted Authorization header.

For example:

header = {
    'Authorization': 'Bearer {}'.format(client.token['access_token'])
}

response = requests.get('https://api.resource-server.com/user', headers=header)

The response in JSON format, via response.json(), could look something like this:

{
   "name": "Aaron Smith",
   "bio": "Software Engineer",
   "avatar_url": "http://api.resource-server.com/user/images/aaron_smith/"
}

Example

A real-life example of an OAuth2 implementation using OAuthLib and Requests can be found in this Django app, which uses GitHub as the OAuth2 provider. You can explore its implementation here.

OAuth Demo

To learn more about integrating OAuth2 in your web applications from common providers, visit these links:

Conclusion

The OAuth2 integration may first appear to be challenging, but this article along with using friendly libraries such as OAuthLib and Requests will help you solidify your understanding of OAuth2. Try implementing a quick example using GitHub as the first provider. Slowly but surely, you'll get better at this as you add more providers to your repertoire.

Merilyn Chesler

Merilyn Chesler

An educator-at-heart, Merilyn Chesler is a software engineer by training and profession. When she's not writing to educate and inform, she can be found delving into Django development. You can enjoy her other writings on Medium.

Share this tutorial

Featured Course

Test-Driven Development with Python, Flask, and Docker

In this course, you'll learn how to set up a development environment with Docker in order to build and deploy a microservice powered by Python and Flask. You'll also apply the practices of Test-Driven Development with pytest as you develop a RESTful API.

Featured Course

Test-Driven Development with Python, Flask, and Docker

In this course, you'll learn how to set up a development environment with Docker in order to build and deploy a microservice powered by Python and Flask. You'll also apply the practices of Test-Driven Development with pytest as you develop a RESTful API.