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.