Django REST APIs with JWT Authentication using dj-rest-auth

Michal Dróżdż
5 min readJul 4, 2024

--

Photo by Emile Perron on Unsplash

What is JWT Authentication?

JWT (JSON Web Token) authentication is a method for securely transmitting information between parties as a JSON object. It is commonly used in web development to authenticate users and provide secure access to protected resources.

Getting started

In this tutorial, we will be setting up a Django project, exposing an API using the Django REST framework (DRF), and securing its endpoint using JWT authentication.

Step 1 — Install required packages

# requirements.txt
Django==5.0.6
djangorestframework==3.15.2
djangorestframework-simplejwt==5.3.1 # JWT token implementation for DRF
dj-rest-auth==6.0.0 # REST API authentication utils

You can see that we’re using a package called dj-rest-auth . This module provides a set of REST API endpoints to handle user registration and authentication tasks.

Step 2 — Basis setup

Add this to your settings.py

INSTALLED_APPS = [
...,
'rest_framework',
'rest_framework.authtoken',
'dj_rest_auth'
]

Usage of rest_framework.authtoken requires us to migrate the database

python manage.py migrate

Set the default authentication class for DRF views

REST_FRAMEWORK = {
...
'DEFAULT_AUTHENTICATION_CLASSES': (
...
'dj_rest_auth.jwt_auth.JWTCookieAuthentication',
)
...
}

Configure dj-rest-auth and djangorestframework-simplejwt

from datetime import timedelta

# djangorestframework-simplejwt
SIMPLE_JWT = {
"ACCESS_TOKEN_LIFETIME": timedelta(hours=1),
"REFRESH_TOKEN_LIFETIME": timedelta(days=1),
}

# dj-rest-auth
REST_AUTH = {
"USE_JWT": True,
"JWT_AUTH_COOKIE": "_auth", # Name of access token cookie
"JWT_AUTH_REFRESH_COOKIE": "_refresh", # Name of refresh token cookie
"JWT_AUTH_HTTPONLY": False, # Makes sure refresh token is sent
}

Full list of dj-rest-auth’s settings and djangorestframework-simplejwt’s settings

Expose authentication endpoints in urls.py

urlpatterns = [
path("admin/", admin.site.urls),
path("api/v1/auth/", include("dj_rest_auth.urls")),
...
]

Step 3— Testing the authentication

First, make sure we have a user we can test with.

python manage.py createsuperuser

Now, using the HTTP client of your choice (Postman, Insomnia, CURL), check the user’s session by making a GET request to /api/v1/auth/user/

GET /api/v1/auth/user/ — Request

As you can see, currently we are not signed in, and we received an HTTP 401 Unauthorized response.

GET /api/v1/auth/user/ — HTTP 401 Response

In order to sign in, call the /api/v1/auth/login/ endpoint, providing your user credentials.

POST /api/v1/auth/login/ — Request

Keep in mind that besides an access token, refresh token, and user details in the response, dj-rest-auth will also set the _auth and _refresh cookies on the client.

POST /api/v1/auth/login/ — Response

If you retry the api/v1/auth/user/ call now (assuming your HTTP client will attach the cookies, which happens by default in clients like Postman or Insomnia), you will get a successful response.

GET /api/v1/auth/user/ — HTTP 200 Response

Step 4 — Available endpoints

Here’s a list of all currently available endpoints. We can see the endpoints we already tried: /user and /login, but also the/token/refresh endpoint that we can call to prolong our session or the /logout endpoint to clear the user’s session.
There are also three endpoints connected to password resetting, but those require additional setup of email sending and might not work out of the box.

/api/v1/auth/login/ dj_rest_auth.views.LoginView rest_login
/api/v1/auth/logout/ dj_rest_auth.views.LogoutView rest_logout
/api/v1/auth/password/change/ dj_rest_auth.views.PasswordChangeView rest_password_change
/api/v1/auth/password/reset/ dj_rest_auth.views.PasswordResetView rest_password_reset
/api/v1/auth/password/reset/confirm/ dj_rest_auth.views.PasswordResetConfirmView rest_password_reset_confirm
/api/v1/auth/token/refresh/ dj_rest_auth.jwt_auth.RefreshViewWithCookieSupport token_refresh
/api/v1/auth/token/verify/ rest_framework_simplejwt.views.TokenVerifyView token_verify
/api/v1/auth/user/ dj_rest_auth.views.UserDetailsView rest_user_details

Refreshing access token

Inside settings.py , we set how long both the access and refresh tokens should be valid. A good practice is to keep the access token lifetime short and refresh it when needed.

If you need to refresh the expired access token, you can use the /api/v1/auth/token/refresh/ endpoint.

POST — /api/v1/auth/token/refresh — HTTP 200 Response

Step 5 — Authorization Header vs. Cookie (optional)

Current implementation returns the access token and refresh token as part of the HTTP response body as well as inside the set-cookie HTTP header. That way, we don’t need to manually attach the authentication credentials (cookies) on every call.

This is very convenient but not always desired. If you do not want to use cookie sessions, you can pass the access token inside the Authorization header.

Here’s a quick guide on how to do that:

Let’s call the login endpoint and grab the access token.

POST /api/v1/auth/login/ — HTTP 200 Response

Now, let’s clear the cookies from our HTTP client and check the user’s session.

GET /api/v1/auth/user/ — HTTP 401 Response

As expected, we don’t have any cookies; therefore, Django couldn’t match any user to our request.

Now, let’s attach the Authorization header to our request and give it a value of Bearer <access_token>

This time, the user was recognized correctly.

Cleanup

Optionally, you can allow users to authenticate only via the Authorization header by slightly changing the settings.

First, add djangorestframework-simplejwt to INSTALLED_APPS.

INSTALLED_APPS = [
...
'rest_framework',
'rest_framework.authtoken',
'rest_framework_simplejwt',
'dj_rest_auth'
]

Next, change the default authentication class for Django REST framework.

REST_FRAMEWORK = {
'DEFAULT_AUTHENTICATION_CLASSES': (
'rest_framework_simplejwt.authentication.JWTAuthentication',
)
}

Lastly, you can disable cookies from being sent in the response by removing these two settings from REST_AUTH.

REST_AUTH = {
"USE_JWT": True,
# "JWT_AUTH_COOKIE": "_auth", # Don't send access token cookie
# "JWT_AUTH_REFRESH_COOKIE": "_refresh", # Don't send refresh token cookie
"JWT_AUTH_HTTPONLY": False, # Makes sure refresh token is sent
}

Conclusion

In this tutorial, we used dj-rest-auth to expose API endpoints that allow you to obtain JWT tokens for our users, validate the session, refresh the access token, and clear the session by logging out.

Code Repository

Example code from this tutorial is available in my GitHub repository:
https://github.com/Mich0232/drf-jwt-tutorial

Further reading
I’m working on a continuation of this tutorial to cover additional topics related to JWT authentication in Django REST framework. I’ll make sure to link them here once they are available.

Thank you for reading!

--

--