Building OAuth2 Services in Django with Django OAuth Toolkit

(Comments)

Most of the modern web applications are not stand alone services, but utilise the capabilities of others' services and focus on solving its core problem well. That is a bit confusing. what do I mean by that? For example most of the web applications allow you to login with your google or facebook accounts. They leave away the hectic tasks of maintaining the user profile information, password management etc. to the services that already do it well. To take another example, most commuting, location based services use google maps (without the need to build their own maps) in their applications, and they put all their efforts on the problem they want to solve.

What is OAuth2?

Let us say you provide a service that needs the user to register himself and create an account. A new visitor who just want to try things might not want to go through the process of registration. He/she might be more inclined to create an account if it does not involve filling up 10 fields, verifying passwords, verifying emails and jumping between browser tabs. You want to let them use their already existing google of facebook accounts. That means you should be able to authenticate them to, say Google, on their behalf. The obvious idea (which was a norm long ago) is to ask their username and password and try logging in to Google to see if that works. Then get their information. But asking and storing the passwords is a risk that you might not want to take. Moreover, how can user trust you with their username and password? And what if he/she changes his/her password? You will not be able to access their information.


The solution here is to use OAuth2 protocol. This is how it works in abstract.

  1. You (the third-party service provider) register yourself with the other provider (Google in our case). This is typically done by creating app. You will be provided with identity credentials (App Id and App Secret).
  2. When a user wants to give you permissions to access his information (login into your service with their Google account), he/she will give your app permissions. When he accepts, the service shares a key with your application (called Access Token) which can be used to get the user's information.
  3. This Access Token expires in sometime and you need to refresh (obtain new token) it using a Refresh Token that will be shared along with Access Token.

Building a service with OAuth capabilities in Django

Now if we want to provide the same capabilities (as that of Google in our case) to our services, we need to implement the OAuth2 protocol which is defined in RFC 6749. But of course, we do not need to build that from scratch. We are going to use Django OAuth Toolkit which provides all the capabilities out of the box.


Install it with

pip install django-oauth-toolkit django-cors-middleware

We will also be needing django-cors-middleware. Then add it to the INSTALLED_APP setting.

INSTALLED_APPS = [
    # Other apps
    'oauth2_provider',
]

Set the URLs as follows, with the url space of your choice. Do not forget to set the URL namespace to oauth2_provider.

urlpatterns = [
    # Other urls
    url(r'^o/', include('oauth2_provider.urls', namespace='oauth2_provider')),
]

Add the CORS middleware and enable it.

MIDDLEWARE = [
     # Other middleware
    'corsheaders.middleware.CorsMiddleware',
    # Other middleware
]

CORS_ORIGIN_ALLOW_ALL = True

Finally migrate the app with python manage.py migrate. We are done with the setup and ready to build our service.

Create a client app

Create a user and login. Assuming that the server is running at http://localhost:8000, visit http://localhost:8000/o/applications/. You should see a screen like this.

Apps page

Click on click here to register a new application. Fill in the form, choose client type as confidential and Authorization Grant Type as authorization-code for this tutorial. Use http://django-oauth-toolkit.herokuapp.com/consumer/exchange/ in Redirect Uris. This is the consumer provided by django-oauth-toolkit to make our testing easy. Now, save the app.

App form

You will be seeing a page like this. Copy the Client Id and Token.

App info

We haven't built any service (API endpoints) yet, but our OAuth authorization server is ready already. To use this, we need to write a consumer application. Fortunately django-oauth-toolkit provides us with a consumer service for our testing purposes.

Visit the consumer page and fill in the fields, Client Id with our OAuth app's client id and Authorization url with http://localhost:8000/o/authorize. Submit the form. The app shows a page with a link (to which our client application - when we build it - should automatically redirected to).

Redirect url

Follow the link and you should be redirected to your local django server page and see a form like this (you will be asked to login if you aren't already).

Authorize

(The next steps must be done in quick succession, so better read the whole paragraph before switching to the practical session) Click on authorize to grant permissions to the application. This page will again be redirected to the consumer app, and you should see that an authorization token is passed to this page (the consumer). Now, the consumer can use this authorization token to get an access token from our service provider. I know there are too many tokens to remember here. This authorization token expires quickly (60 seconds in our case). This step of obtaining access token must be (there is no reason not to) automated by a consumer application. To get the access token fill in the application's Client id, Client secret and the field Token URL to http://localhost:8000/o/token/ and then submit the form.

Authorization token

The consumer receives the access token.

Access token

Now that the consumer has obtained the access token, it should be able to make use of our OAuth protected services (APIs) on our user's behalf. Let us see, how to build the protected API endpoints.

Building OAuth protected API end-points

We will use the generic views that Django OAuth Toolkit provides to create our protected API endpoints. Create a view as follows.

from django.http import HttpResponse
from oauth2_provider.views.generic import ProtectedResourceView

class MyProtectedEndPoint(ProtectedResourceView):
    def get(self, request, *args, **kwargs):
        return HttpResponse('Hello, there!!')

And add the view to your URL configuration and try to visit the url in the browser. You will see a 403 error stating that access is denied. Something like this.

403 error

We can also use a client program like curl to send a get request with the command

curl -i -H "Accept: application/json" -H "Content-Type: application/json" -X GET http://localhost:8000/api/posts/protected_view/

The result will look like this.

Curl forbidden

Now this end point must be accessible to the consumer when it provides the access token. Visit the consumer page, fill in the API Url and Access Token. Before clicking the 'GET' button open your browser's network tab in developer tools (Ctrl+Shift+i in google chrome), then click on 'GET'. The response should be a '200 OK'.

OAuth2 get request

We can verify the result in the network tab.

200 OK get response Response text

We can test this with curl by passing the access token as part of the Authorization Bearer Token with command

curl -i -H "Accept: application/json" -H "Authorization: Bearer aVVkoxH600GX0L8yh0wO06EhCFWeVA" -H "Content-Type: application/json" -X GET http://localhost:8000/api/posts/protected_view/

The result should look something like this.

Curl 200 OK response

So that is it. We will see how to provide authentication with OAuth in the next post.

Comments

Recent Posts

Archive

2019
2018
2017
2016
2015
2014

Tags

Authors

Feeds

RSS / Atom