Adding JWT Authentication to Python and Django REST Framework Using Auth0
In this tutorial we'll learn how to add JWT authentication to an API built with Django REST framework. Basically we'll use the djangorestframework-jwt
package for adding JWT authentication as you would normally do except that we'll change JWT_AUTH
to use Auth0.
This tutorial assumes you already have a development machine with Python 3 and pip installed and will cover the following points:
- We'll see how to create a virtual environment, install Django and the other dependencies (Django REST framework and
djangorestframework-jwt
) - We'll see how to create an Auth0 API
- We'll see how to integrate Auth0 JWT authentication with Django
- We'll briefly talk about using Auth0 Rules for detecting signup
- We'll see how to add some Django views for testing JWT
- We'll see how to use Postman for testing JWT authentication with Auth0
Creating the Django Project
So head over to your terminal then create a new virtual environment and activate it using the venv
module in your current working directory:
python3 -m venv ./myenv
source myenv/bin/activate
Next install Django using pip
:
pip install django
Now you'll need to create a new Django project using:
django-admin startproject auth0-django-example
Next create a new application in your project
cd auth0-django-example
python manage.py startapp customers
Add customers
to the installed apps in your project' settings.py
file:
INSTALLED_APPS = [
'django.contrib.admin',
'django.contrib.auth',
'django.contrib.contenttypes',
'django.contrib.sessions',
'django.contrib.messages',
'django.contrib.staticfiles',
'customers'
]
Next migrate your database then start the development server
python manage.py migrate
python manage.py runserver
You can visit your app at http://localhost:8000
Create an Auth0 API
Head over to your Auth0 dashboard then create an API
Go to the API section then click on the CREATE API button which will show a form where you need to enter your API details
Integrating Auth0 with Django
Now head back to your terminal then install Django REST framework and djangorestframework-jwt
package for handling JWT authentication using pip
pip install djangorestframework
pip install djangorestframework-jwt
pip install cryptography
pip install python-jose
Add rest_framework
and rest_framework_jwt
to the installed apps in settings.py
:
INSTALLED_APPS = [
'rest_framework',
'rest_framework_jwt'
]
Next you'll need to setup djangorestframework-jwt
to use Auth0 central server for JWT authentication by follwing a few steps.
First add JSONWebTokenAuthentication
to DEFAULT_AUTHENTICATION_CLASSES
:
REST_FRAMEWORK = {
'DEFAULT_PERMISSION_CLASSES': (
'rest_framework.permissions.IsAuthenticated',
),
'DEFAULT_AUTHENTICATION_CLASSES': (
'rest_framework_jwt.authentication.JSONWebTokenAuthentication',
),
}
Secondly import the follwing libs in your settings.py
file:
import json
from six.moves.urllib import request
from cryptography.x509 import load_pem_x509_certificate
from cryptography.hazmat.backends import default_backend
Finally add this code to settings.py
:
AUTH0_DOMAIN = '<YOUR_AUTH0_DOMAIN>'
API_IDENTIFIER = '<YOUR_API_IDENTIFIER>'
PUBLIC_KEY = None
JWT_ISSUER = None
if AUTH0_DOMAIN:
jsonurl = request.urlopen('https://' + AUTH0_DOMAIN + '/.well-known/jwks.json')
jwks = json.loads(jsonurl.read().decode('utf-8'))
cert = '-----BEGIN CERTIFICATE-----\n' + jwks['keys'][0]['x5c'][0] + '\n-----END CERTIFICATE-----'
certificate = load_pem_x509_certificate(cert.encode('utf-8'), default_backend())
PUBLIC_KEY = certificate.public_key()
JWT_ISSUER = 'https://' + AUTH0_DOMAIN + '/'
def jwt_get_username_from_payload_handler(payload):
return 'someusername'
JWT_AUTH = {
'JWT_PAYLOAD_GET_USERNAME_HANDLER': jwt_get_username_from_payload_handler,
'JWT_PUBLIC_KEY': PUBLIC_KEY,
'JWT_ALGORITHM': 'RS256',
'JWT_AUDIENCE': API_IDENTIFIER,
'JWT_ISSUER': JWT_ISSUER,
'JWT_AUTH_HEADER_PREFIX': 'Bearer',
}
But of course you need to replace AUTH0_DOMAIN
with your own Auth0 domain and API_IDENTIFIER
with your own API identifier.
Please note that you need to create a user in your Django database with a someusername
username for the JWT authentication to work.
The custom jwt_get_username_from_payload_handler
that we are using is very simple, it maps your Auth0 users to one user in your Django database.
Because Auth0 already takes care of managing users and profiles for you so most of the time you don't have to store users locally i.e in your Django database unless you need to have users information in your database for some reason.
In this case you'll need to create a more advanced implementation. You can use this custom method instead:
def jwt_get_username_from_payload_handler(payload):
return payload.get('sub').replace('|', '.')
But that's not the end of story: You need to create a Django user when a user successfully signs up using Auth0.
Using Auth0 Rules for Detecting Signup
For this task you need to use Auth0 Rules
Rules are functions written in JavaScript that are executed in Auth0 as part of the transaction every time a user authenticates to your application. They are executed after the authentication and before the authorization.
Rules allow you to easily customize and extend Auth0's capabilities. They can be chained together for modular coding and can be turned on and off individually. Source
You can also see this example of a signup rule
Adding Django Views
Now let's add the code to test the Auth0 JWT authentication:
In customers/views.py
add two view functions
from rest_framework.decorators import api_view
from django.http import HttpResponse
def public(request):
return HttpResponse("You don't need to be authenticated to see this")
@api_view(['GET'])
def private(request):
return HttpResponse("You should not see this message if not authenticated!");
In urls.py
add:
from django.conf.urls import url
from . import views
urlpatterns = [
url(r'^api/public/', views.public),
url(r'^api/private/', views.private)
]
Testing JWT Authentication with Postman
Go to your API dashboard then to the Test tab then get a token you can use to test authentication
Next navigate with your web browser to http://localhost:8000/api/private/
. You should get Authentication credentials were not provided.
Now let's use Postman for testing our endpoint: Open Postman then enter the URL for the endpoint then select Authorization tab.
For the TYPE select Bearer Token and in the right area enter the access token you get from Auth0 for testing.
Finally press the Send button, you should get: You should not see this message if not authenticated! as in the screenshot
Conclusion
In this tutorial we have created a simple Django application that uses Django REST framework and Auth0 for adding JWT authentication.
-
Date: