Michael Washburn Jr's Blog

User Authentication with Django REST Framework

Written by Michael Washburn Jr | Nov 14, 2017 7:11:28 AM

User Authentication is a simple concept, but when it comes to properly implementing it in Django, things can get complicated. Django offers an abundance of different authentication mechanisms: BasicAuthentication, TokenAuthentication, SessionAuthentication, and various ways to implement custom authentication mechanisms.

The introduction of Django REST Framework did great things for Django. However, it introduces another layer of confusion, and often leaves the developer asking “Which authentication mechanism should I use?”
If you’re building a web app backed by a Django REST Framework API, and that web app needs to handle user authentication, then you probably have the following requirements for user authentication:

  • Users must be able to authenticate with the API using a username and password.
  • Authentication with the API should return a token for future requests.
  • Authentication tokens should expire after a set amount of time.
  • Users should be able to refresh their token with an API request.
  • Users should be able to change their passwords.

These seem like simple requirements, but none of the built-in authentication mechanisms fully satisfy these needs, or lack the necessary amount of security. In this article, I’m going to show you what has become my favorite way of getting user authentication working in my web apps. It’s a great little solution for web apps that have to manage user sessions.

I’ll assume that you already have a working Django REST Framework project for this tutorial. If you don’t check out my series on starting a new Django REST Framework project.

Setting Up User Authentication and Registration

django-rest-auth is a great little package which encompasses almost everything you need to get user authentication up and running in your API. On it’s own, it fulfills a majority of the requirements I outlined above.

What Modifications Do We Need to Make?

To fulfill our needs, we’re going to also configure django-rest-auth’s optional registration app. This will allow us to easily register new user accounts without any custom code on our part.

By default, django-rest-auth uses standard Django tokens to allow users to authenticate. However, these tokens never change. So we’re also going to configure django-rest-auth to use django-rest-framework-jwt: a package providing a secure JWT implementation. These tokens can be configured to expire after a set amount of time, which is much more secure than the default token implementation.

Installation

To get started, let’s install the three packages we’ll be using.

pip install django-rest-auth
pip install djangorestframework-jwt
pip install django-allauth

Configure the Django Settings

Now that we have our packages installed, add the following apps to your settings file.

INSTALLED_APPS = (
    ...
    'rest_framework',
    'rest_auth',
    'django.contrib.sites',
    'allauth',
    'allauth.account',
    'rest_auth.registration',
)

At this point, the django-rest-auth tutorial would also tell you to add the rest_framework.authtoken app as well. However, since we’re going to use JWTs, we don’t need to do this.

To use JSON Web Tokens (JWTs), we’ll have to also add the following configuration settings:

import datetime

# Configure the JWTs to expire after 1 hour, and allow users to refresh near-expiration tokens
JWT_AUTH = {
    'JWT_EXPIRATION_DELTA': datetime.timedelta(hours=1),
    'JWT_ALLOW_REFRESH': True,
}

# Make JWT Auth the default authentication mechanism for Django
REST_FRAMEWORK = {
    'DEFAULT_AUTHENTICATION_CLASSES': (
        'rest_framework_jwt.authentication.JSONWebTokenAuthentication',
    ),
}

# Enables django-rest-auth to use JWT tokens instead of regular tokens.
REST_USE_JWT = True

To make the registration app work, we’ll also have to add the following setting, which is required for the django.contrib.sites dependency.

SITE_ID = 1

That’s all the setting changes that we’ll need to start adding our views.

Adding our Views

Django-rest-auth and django-rest-framework-jwt provide a few views for us that we can enable in our api.

Add the following to your urls.py  file to enable login, logout, and registration (and the rest of the django-rest-auth endpoints listed here).

urlpatterns = [
    ...
    url(r'^rest-auth/', include('rest_auth.urls')),
    url(r'^rest-auth/registration/', include('rest_auth.registration.urls'))
]

There’s still one more thing we’ll have to do if we want to allow users to refresh their tokens without logging in again. django-rest-framework-jwt has a view we can include which will do just this. Add the refresh_jwt_token view to your urls as shown below.

from rest_framework_jwt.views import refresh_jwt_token

urlpatterns = [
    ...
    url(r'^rest-auth/', include('rest_auth.urls')),
    url(r'^rest-auth/registration/', include('rest_auth.registration.urls')),
    ...
    url(r'^refresh-token/', refresh_jwt_token),
]

Now we’re done! Run python manage.py migrate to make all the necessary database changes, and then you will be able to start using these.

Testing our Views

Now that the heavy lifting is done, I could end this blog post. A lot of people probably would. I mean, I told you everything you need to know to get this working, right?

Wrong.

Now I’m going to show you how to actually use the API we just built. In my opinion, nothing is worse than knowing exactly how to configure something to work, and then not knowing how to use it.

When I’m doing this type of testing, I usually use an app called Postman. I’d recommend getting that, but you could also make these HTTP requests on the command line using a tool like cURL.

Below, I’ll give you the endpoint, method, and payload for each action we want to perform. You can plug this information into Postman or use it in an AJAX request in your code to use them.

Register

Method: POST
Endpoint: /rest-auth/registration/
Payload:

{
    "username": "USERNAME",
    "password1": "PASSWORD",
    "password2": "PASSWORD",
    "email": "OPTIONAL_EMAIL"
}

Login

Method: POST
Endpoint: /rest-auth/login/
Payload:

{
    "username": "USERNAME",
    "password": "PASSWORD"
}

Logout

Method: POST
Endpoint: /rest-auth/logout/
Headers: Authorization: JWT YOUR_TOKEN_HERE

Refresh Token

Method: POST
Endpoint: /refresh-token/
Payload:

{
    "token": "YOUR_OLD_TOKEN"
}

That’s it, use Postman, curl, or another tool to build requests based on the above descriptions and you’ll be all set!

Web app development is slowly trending towards having a separate UI and API.  With that, comes a different need for user authentication. I hope this tutorial helps you fulfill that need the best way possible.

Let me know if you have any questions or suggestions in the comments below! Stay tuned for a blog post on API key authentication, for those of you creating RESTful web services.