yeti logo icon
Close Icon
contact us
Yeti postage stamp
We'll reply within 24 hours.
Thank you! Your message has been received!
A yeti hand giving a thumb's up
Oops! Something went wrong while submitting the form.

OAuth2 with Django REST Framework

By
-
January 20, 2015

UPDATED November 25, 2015

This post is part 2 of a series on using OAuth with Django REST Framework. Part 1 is the series overview and I share some of my thoughts on the process. Part 3 is about social auth (e.g., Facebook, Twitter authentication) using DRF. Part 4 offers a richer explanation of server vs. client oauth flows, and part 5 is about integrating parts 2 & 3.

Here at Yeti we build our APIs with Django REST Framework and use the OAuth2 scheme using Django OAuth Toolkit. I'm no OAuth expert and it took me awhile to figure it all out — in fact, this is the second version of this post! Hopefully this blog post will save others some trouble; it will show you everything you need to set up OAuth2 for your own application using DRF.

This post is NOT about setting up authentication with third-party services like Facebook (see Part 3 instead). It is also not about creating an authentication service for apps other than your own to use.

Setup

I'm assuming you already have a User model and have DRF setup.

  1. pip install django-oauth-toolkit
  2. Add 'oauth2_provider' to installed apps
  3. Add DOT to your authentication classes for DRF in settings.py
  4. REST_FRAMEWORK = {
       'DEFAULT_AUTHENTICATION_CLASSES': (
           'oauth2_provider.ext.rest_framework.OAuth2Authentication',
       ),
    }
  5. Add DOT to your urls.py
  6. urlpatterns = patterns('',
       url(r'^', include(router.urls)),
       url(r'^o/', include('oauth2_provider.urls', namespace='oauth2_provider')),
       url(r'^admin/', include(admin.site.urls)),
    )
  7. python manage.py migrate

How all this application and client stuff is working

Setting up OAuth for your own application can be confusing. For me, I was used to oauth flows with third-party services like Facebook and Twitter, but it took me a bit to wrap my head around how that would work for my app and our users. It doesn't help that oauth can be implemented in different ways (1.0 vs 2.0, different grant types, etc.).

When you use a third-party service

When you do your own OAuth

Essentially, the way OAuth works, there needs to be an application that a user is authenticating with. But now our app is the service providing authentication, so what is the appilcation supposed to be? Nothing really. It's just a dummy application that we set up. You can think of it as representing your front-end application if that helps.

Creating an application

In your Django admin or shell, you can create a new oauth2_provider.models.Application. Set client type to "public" and grant type to "resource owner password based". The name can just be whatever makes sense to you (e.g., "iOS App", "JS Frontend"), and the application should be owned by your admin user.

Note: The Django OAuth Toolkit tutorial says to make the client type "confidential". You can if you want, but since this app is actually going to be living on a public, insecure client (browser, mobile device), it makes more sense for the client type to be "public".

Example Sign Up

You don't have to use this, you're welcome to just make a user in the admin, but here's a full example:

serializers.py

from rest_framework import serializers

class SignUpSerializer(serializers.ModelSerializer):
   class Meta:
       model = User
       fields = ('username', 'password')
       write_only_fields = ('password',)

views.py

from rest_framework import generics
from permissions import IsAuthenticatedOrCreate

class SignUp(generics.CreateAPIView):
   queryset = User.objects.all()
   serializer_class = SignUpSerializer
   permission_classes = (IsAuthenticatedOrCreate,)

permissions.py

from rest_framework import permissions

class IsAuthenticatedOrCreate(permissions.IsAuthenticated):
   def has_permission(self, request, view):
       if request.method == 'POST':
           return True
       return super(IsAuthenticatedOrCreate, self).has_permission(request, view)

urls.py

urlpatterns = patterns('',
   url(r'^sign_up/$', views.SignUp.as_view(), name="sign_up"),
)

Request / Response (in JSON)

request:

{
   "username": "django.pony",
   "password": "djangsta"
}

response:

{
   "username": "django.pony"
}

Get your token

The DOT docs say that you can get your token with the following request:

curl -X POST -d "grant_type=password&username=<user_name>&password=<password>" http://<client_id>:<client_secret>@localhost:8000/o/token/

Let's translate that.

The mechanics of making this request with your Angular / iOS / whatever client are beyond the scope of this blog post, but I use a tool called Postman when playing around with APIs and the request looks like this:

You should get a response that looks like this:

{
   "access_token": "THIS IS THE IMPORTANT PART",
   "token_type": "Bearer",
   "expires_in": 36000,
   "refresh_token": "xyz456",
   "scope": "read write groups"
}

Using your token

From here out, using your token is straightforward. To make an authenticated request, just pass the Authorization header in your requests. It's value will be "Bearer YOUR_ACCESS_TOKEN".

Logging in

The last missing piece of this is handling login. If your token expires or a user logs out of your application, you'll need to get a new token. Logging in works the exact same as the last request to /o/token/: you pass client id, grant type, username, and password, and you'll get a fresh access token back.

Logging out

Remember, the only thing that lets the server know that your subsequent requests are authorized is that token you are passing along. To log out (or make an unauthorized request), just delete the access token on your front end.

In summary

These are the endpoints we just set up:

EndpointAuthRequestResponsesign_up/username, passwordusernameo/token/username, password, client_idtoken (and some other stuff)everything elseOAuth2 (formatted as: Bearer YOUR_TOKEN)

You should now be able to sign up, then hit the o/token/ endpoint, and then be on your merry way.

You Might also like...

Shopify Checkout Using UI Extensions

At Yeti we recently created a custom Shopify App using Checkout UI extensions to pull real-time data from a client’s Enterprise Resource Planning (ERP) system into Shopify. By the end of this article you will better understand what Shopify Checkout UI extensions are, how to approach building them, and some of the things to keep in mind during the implementation process.

colorful swirlsAn Introduction to Neural Networks

Join James McNamara in this insightful talk as he navigates the intricate world of neural networks, deep learning, and artificial intelligence. From the evolution of architectures like CNNs and RNNs to groundbreaking techniques like word embeddings and transformers, discover the transformative impact of AI in image recognition, natural language processing, and even coding assistance.

A keyboardThe Symbolicon: My Journey to an Ineffective 10-key Keyboard

Join developer Jonny in exploring the Symbolicon, a unique 10-key custom keyboard inspired by the Braille alphabet. Delve into the conceptualization, ideas, and the hands-on process of building this unique keyboard!

Browse all Blog Articles

Ready for your new product adventure?

Let's Get Started