In this article we’ll learn how to use simple JWT authentication with the Django Rest Framework. Before we understand Simple JWT Authentication, lets understand what is JWT ?
Dataneard · Follow
9 min read · Feb 12, 2024
--
JSON Web Token(JWT) also (pronounced “jot”) is an open standard that is used to securely transmit the data or information between the client and server as a JSON object. Each JWT contains encoded JSON objects, which have set of claims. A claims may assert who issues the token, what are the permissions granted to the clients , or how long the token is valid. JWT are signed using cryptographic algorithm to ensure that the claims cannot be altered after the token is issued.
JWT is a single line and encoded string which have three parts.
- Header : It contains two keys, a token type value and algorithm value used in encoding.
{
"alg": "HS256",
"typ": "JWT",
}
2 . Payload : Payload consist of claims. Custom claims can also be added in the payload part.
{
"sub" : "user1",
"id" : 1,
"name": "Rachel Green",
"admin": true
}
3. Signature : It is most important part of JSON Web Token. Header and Payload is encoded using Base64url encoding. Then these two are concatenated with a separator. And whole code is provided to the client in the authentication process.
HMACSHA256(
base64UrlEncode(header) + "." +
base64UrlEncode(payload),
secret)
How Does JWT Works ?
In authentication process whenever a user or client wants to login to the web application, then user need to send their login credentials like username or password to server and request for a JWT token form the server.
Then server provide a JWT to the User only when user is verified. User then send that token to the server back to request for the accessToken to access the information of their own. The server checks and verify whether the accessToken is valid or not. If the token is verified then user can successfully login to their account and access their own information stored in the database.
What is Simple JWT ?
Simple JWT is used for authentication in DRF, it basically generates a token for the client in the form of encoded JSON object.
Before starting to use simple jwt, lets first define models for the user data which we implement in our authentication mechanism.
Part 1 : Create Model and Admin
The very first step is creating a Django project. If you are a beginner in Django, and want to learn how to create a project just go through my article Here.
When your project setup is completed, open account/models.py file in your editor and create a model for user to login and register to their account.
We’ll use custom user model for authentication of the users. By Default Django provides authenticated of the user by username and password only but if want to customize the authentication system of user like authenticating through email or phone etc, then we use custom user model. Here in this project we are authenticating the user through their email, name and password. Copy and paste the below code in your models.py file.
from django.db import models
from django.contrib.auth.models import AbstractUser, BaseUserManagerclass UserManager(BaseUserManager):
use_in_migration = True
def create_user(self, email, password=None, **extra_fields):
if not email:
raise ValueError('Email is Required')
user = self.model(email=self.normalize_email(email), **extra_fields)
user.set_password(password)
user.save(using=self._db)
return user
def create_superuser(self, email, password, **extra_fields):
extra_fields.setdefault('is_staff', True)
extra_fields.setdefault('is_superuser', True)
extra_fields.setdefault('is_active', True)
if extra_fields.get('is_staff') is not True:
raise ValueError('Superuser must have is_staff = True')
if extra_fields.get('is_superuser') is not True:
raise ValueError('Superuser must have is_superuser = True')
return self.create_user(email, password, **extra_fields)
class UserData(AbstractUser):
username = None
name = models.CharField(max_length=100, unique=True)
email = models.EmailField(max_length=100, unique=True)
date_joined = models.DateTimeField(auto_now_add=True)
is_admin = models.BooleanField(default=False)
is_active = models.BooleanField(default=True)
is_staff = models.BooleanField(default=False)
is_superuser = models.BooleanField(default=False)
objects = UserManager()
USERNAME_FIELD = 'email'
REQUIRED_FIELDS = ['name']
def __str__(self):
return self.name
account/models.py
Basically in the above code we created a class UserData which extends the UserManager class. The ‘username’ is set to be none because we want to authenticate the user by its unique email id instead of a username.
We have written ‘email’ in the USERNAME_NAME field which tells django that we want to input email id instead of username when authenticating.
REQUIRED_FIELD is set to be ‘name’ tells django that inserting user name is compulsory for every user.
The create_user() method creates, saves, and returns the User. And the create_superuser() method sets the is_staff and is_superuser to True.
Specify the custom model as the default user model for your project using the AUTH_USER_MODEL
writing in your settings.py
AUTH_USER_MODEL = 'account.UserData'
Now we’ll run migrations. We run makemigartions and migrate command to create a new table in the database.
python manage.py makemigartions account
We’ll get output like this in our command Line
Migrations for 'account':
account/migrations/0001_initial.py
- Create model UserData
Then run command for migrating the tables in database.
python manage.py migrate
we’ll see output like this is command line.
Operations to perform:
Apply all migrations: account, admin, auth, contenttypes, sessions
Running migrations:
Applying contenttypes.0001_initial... OK
Applying contenttypes.0002_remove_content_type_name... OK
Applying auth.0001_initial... OK
Applying auth.0002_alter_permission_name_max_length... OK
Applying auth.0003_alter_user_email_max_length... OK
Applying auth.0004_alter_user_username_opts... OK
Applying auth.0005_alter_user_last_login_null... OK
Applying auth.0006_require_contenttypes_0002... OK
Applying auth.0007_alter_validators_add_error_messages... OK
Applying auth.0008_alter_user_username_max_length... OK
Applying auth.0009_alter_user_last_name_max_length... OK
Applying auth.0010_alter_group_name_max_length... OK
Applying auth.0011_update_proxy_permissions... OK
Applying auth.0012_alter_user_first_name_max_length... OK
Applying account.0001_initial... OK
Applying admin.0001_initial... OK
Applying admin.0002_logentry_remove_auto_add... OK
Applying admin.0003_logentry_add_action_flag_choices... OK
Applying sessions.0001_initial... OK
Now we are able to see a db.sqlite3 file created in our django project directory. It is a db file which contains all the records of the table which we have created in our models.
Make changes in admin.py of our project.
#account/admin.pyfrom django.contrib import admin
from .models import UserData
admin.site.register(UserData)
account/admin.py
Now create superuser with the following command
python manage.py createsuperuser
When running the above command we’ll see that we are asked to create a superuser by email, name and password. Create required email, name and password for your superuser then run the project by command
python manage.py runserver
Then visit to the url http://127.0.0.1:8000/admin/ you will get output like this
Now we’ll login here by superuser’s email and password.
We are now able to see admin dashboard. It is a built-in site by django which is created as per we create our models. In this site we can perform read, create, update and delete operation of our data. Inside Django Admin Dashboard we can see a table named users. This is the same table which we had created in the our models.py of our project by the name UserData. This table contains all the record of the user created.
Part 2 : Create API’s for the UserData
Next Step is to install Django Rest Framework in your Project Directory. Django Rest Framework (DRF) is a toolkit build in web application which is used for creating web API’s. It returns web API’s in the form of raw JSON. Install DRF using following command
pip install djangorestframework
When drf is installed, add ‘rest_framework’ in your settings.py file.
INSTALLED_APPS = [
'django.contrib.admin',
'django.contrib.auth',
'django.contrib.contenttypes',
'django.contrib.sessions',
'django.contrib.messages',
'django.contrib.staticfiles',
'account'
'rest_framework',
]
Then we declare serializers for UserData. Serializers convert data such as models and queryset into JSON data which is easily understandable by the javascript.
Create a new file name serializers.py in your accounts app.
from rest_framework import serializers
from .models import UserDataclass UserSerializer(serializers.ModelSerializer):
class Meta:
model = UserData
fields = ["id", "email", "name", "password"]
def create(self, validated_data):
user = UserData.objects.create(email=validated_data['email'],
name=validated_data['name']
)
user.set_password(validated_data['password'])
user.save()
return user
account/serializers.py
Now we’ll create our views for registering the user. Open views.py of account app and copy the below code.
from django.shortcuts import render
from rest_framework.views import APIView
from .serializers import UserSerializer
from rest_framework.response import Response# view for registering users
class RegisterView(APIView):
def post(self, request):
serializer = UserSerializer(data=request.data)
serializer.is_valid(raise_exception=True)
serializer.save()
return Response(serializer.data)
account/views.py
Part 3 : Define URL for Views
Create a new file name urls.py in your accounts app. And copy the below code
from django.urls import path
from .views import RegisterViewurlpatterns = [
path('api/register/', RegisterView.as_view(), name="sign_up"),
]
account/urls.py
Now we need to register the urls.py file of account app to the root project i.e. blogSite. Change the urls.py of blogSite like this
"""blogSite URL Configuration
The `urlpatterns` list routes URLs to views. For more information please see:
https://docs.djangoproject.com/en/4.0/topics/http/urls/
Examples:
Function views
1. Add an import: from my_app import views
2. Add a URL to urlpatterns: path('', views.home, name='home')
Class-based views
1. Add an import: from other_app.views import Home
2. Add a URL to urlpatterns: path('', Home.as_view(), name='home')
Including another URLconf
1. Import the include() function: from django.urls import include, path
2. Add a URL to urlpatterns: path('blog/', include('blog.urls'))
"""
from django.contrib import admin
from django.urls import path, includeurlpatterns = [
path('admin/', admin.site.urls),
path('account/', include('account.urls')),
]
blogSite/urls.py
Part 4 : Using Simple JWT to Login User
We will use simple JWT to login user an generate access and refresh Token for authentication of user. Install simple JWT in your project directory with the pip command.
pip install djangorestframework-simplejwt
Then add ‘rest_framework_simplejwt’ in your settings.py file
INSTALLED_APPS = [
‘django.contrib.admin’,
‘django.contrib.auth’,
‘django.contrib.contenttypes’,
‘django.contrib.sessions’,
‘django.contrib.messages’,
‘django.contrib.staticfiles’,
‘account’
‘rest_framework’,
‘rest_framework_simplejwt’,
]
Then our django project must be configured to use the simple jwt library. In settings.py file , add rest_framework_simplejwt.authentication.JWTAuthentication to the list of authentication classes:
REST_FRAMEWORK = {
'DEFAULT_AUTHENTICATION_CLASSES': (
'rest_framework_simplejwt.authentication.JWTAuthentication',
),
}
In our app level urls.py we’ll add routes for simple jwt as TokenObtainPairView and TokenRefreshView views.
from django.urls import path
from user.views import RegisterView
from .views import UserListView
from rest_framework_simplejwt.views import (
TokenObtainPairView,
TokenRefreshView,
)urlpatterns = [
path('api/login/', TokenObtainPairView.as_view(), name='token_obtain_pair'),
path('api/login/refresh/', TokenRefreshView.as_view(), name='token_refresh'),
path('api/register/', RegisterView.as_view(), name="sign_up"),
path('users/', UserListView.as_view(), name='user-list'),
]
account/url.py
Yayy !! We have created the authentication part of our project. Now its time to test the API’s. For Testing our API’s we use postman app. For doing so go to the url https://www.postman.com/ and start a new workspace.
In the above image we’ll see a GET Request field. Change that field to POST, because we are trying to register the user, so we POST request the user data into the database.
Now enter “http://127.0.0.1:8000/account/api/register/” in the url field.
Select the Body option. Then select form-data radio button and create new user by inserting email, name and password of the user
Then click on the Send button. We’ll see the JSON data below which contains our new user’s information.
Now we’ll login the registered user with correct email and password. Replace the url with http://127.0.0.1:8000/account/api/login/
Then on the body option give the correct credentials for login.
When we click on the send button we get two types of token. An Access token and a Refresh Token.
Access Token : Access token is the encoded string which contains information about user, permissions etc. Token are used as a bearer token, Bearer means which hold data in it. An access token is put in the Authorization header of your request for the user’s API.
Refresh Token : An access tokens have very short life span because of the security purpose. When it expires a user need to generated new access token for authentication. So refresh token is used to request new access tokens without user interaction.
We can also customize the behavior of simple JWT by changing some of the settings variables in the settings.py. Copy and paste the following code in settings.py file.
from datetime import timedelta
SIMPLE_JWT = {
'ACCESS_TOKEN_LIFETIME': timedelta(minutes=60),
'REFRESH_TOKEN_LIFETIME': timedelta(days=30),
}
ACCESS_TOKEN_LIFETIME : Here we specify how long an access token is valid. We set it to 60 minutes, means after 60 minutes the access token expires.
REFRESH_TOKEN_LIFETIME : Here we specify how long a refresh token is valid. We set it to 30 days, means after 30 days, the refresh token is expired and user need to login again.
Many other features of simple JWT token are also customizable which we’ll find in the simple JWT documentation.
So that’s it for now, we have learned about simple JWT and its implementation. We created authentication of the user and also created API’s. Now your project is ready with the simple JWT authentication on the backend.
In my up coming articles we’ll create a responsive website and learn how to use JSON web Token for accessing the user information.