Use JWT in django

2019-06-06

let's see how to use JWT(Json Web Token) for API in django project.

Outline

I try to develop django API server for login, updating in React Native App. at this time, I want to implement JWT(Json Web Token) authentication, that is used nomally between App and API server, in django. in this blog post, we’ll see how to implement JWT in django by using Django REST framework JWT.

you can see the source code introduced in this blog on Github. see the linke below.

Prepare django Project

you can see how to prepare django project on the previous blog post series. if you want more details about how to make django project, see the links below.

in this blog post, we won’t see how to install and configure django project. just we’ll see simply to prepare the project to be able to talk about JWT.

execute the command below to create django project.

django-admin startproject django_jwt

connect database and migrate the tables to see the blog below.

after connecting the database, execute the command below to create an administrator(superuser).

python manage.py createsuperuser

create Blog django App and Post Model by referring the blog post below.

and then add test data by referring the blog post below.

Install Django REST framework JWT

implementing JWT is a little bit hard. so almost platforms have well-made module or library. in here, we’ll use Django REST framework JWT to implement JWT.

execute the command below to install Django REST framework JWT

pip install djangorestframework djangorestframework-jwt
  • djangorestframework: this module helps to implement Restful API in django.
  • djangorestframework-jwt: this helps to implement JWT in django Restful API.

after installing, don’t forget to update requirements.txt.

pip freeze > requirements.txt

configure Django Rest framework JWT

open and modify django_jwt/settings.py to configure Django Rest framework JWT like below.

...
REST_FRAMEWORK = {
    'DEFAULT_PERMISSION_CLASSES': (
        'rest_framework.permissions.IsAuthenticated',
    ),
    'DEFAULT_AUTHENTICATION_CLASSES': (
        'rest_framework_jwt.authentication.JSONWebTokenAuthentication',
        'rest_framework.authentication.SessionAuthentication',
        'rest_framework.authentication.BasicAuthentication',
    ),
}

JWT_AUTH = {
    'JWT_SECRET_KEY': SECRET_KEY,
    'JWT_ALGORITHM': 'HS256',
    'JWT_ALLOW_REFRESH': True,
    'JWT_EXPIRATION_DELTA': datetime.timedelta(days=7),
    'JWT_REFRESH_EXPIRATION_DELTA': datetime.timedelta(days=28),
}
...

see more details,

REST_FRAMEWORK = {
    'DEFAULT_PERMISSION_CLASSES': (
        'rest_framework.permissions.IsAuthenticated',
    ),
    'DEFAULT_AUTHENTICATION_CLASSES': (
        'rest_framework_jwt.authentication.JSONWebTokenAuthentication',
    ),
}

it’s configurations about djangorestframework.

  • use rest_framework.permissions.IsAuthenticated to check login(Permission) status class(DEFAULT_PERMISSION_CLASSES)
  • use JWT(rest_framework_jwt.authentication.JSONWebTokenAuthentication) to login(Authentication) class.
JWT_AUTH = {
    'JWT_SECRET_KEY': SECRET_KEY,
    'JWT_ALGORITHM': 'HS256',
    'JWT_ALLOW_REFRESH': True,
    'JWT_EXPIRATION_DELTA': datetime.timedelta(days=7),
    'JWT_REFRESH_EXPIRATION_DELTA': datetime.timedelta(days=28),
}
  • JWT_SECRET_KEY: JWT secret key. in here, we use django secret key, but it’s better to use another key in production.권장합니다.
  • JWT_ALGORITHM: JWT encryption algorithm.
  • JWT_ALLOW_REFRESH: use JWT token refresh or not
  • JWT_EXPIRATION_DELTA: JWT token expired period.
  • JWT_REFRESH_EXPIRATION_DELTA: JWT token refresh expired period.

it’s confusing to understand JWT_EXPIRATION_DELTA and JWT_REFRESH_EXPIRATION_DELTA. in above case, JWT token will be expired after 7 days if you don’t refresh it. that means user will be logout after 7 days from first login. also, if we refresh the token in 7 days, after 28 days, token will be expired. that means even if we refresh JWT token in every 7 days, after 28 days, user will be logout.

Set URL for Django Rest framework JWT

we need to add URL for JWT authentication. open and modify django_jwt/url.py file like below.

from django.contrib import admin
from django.urls import path, include
from rest_framework_jwt.views import obtain_jwt_token, verify_jwt_token, refresh_jwt_token

urlpatterns = [
    path('admin/', admin.site.urls),
    path('api/token/', obtain_jwt_token),
    path('api/token/verify/', verify_jwt_token),
    path('api/token/refresh/', refresh_jwt_token),
    path('api/blog/', include('blog.urls'))
]
  • from rest_framework_jwt.views import obtain_jwt_token, verify_jwt_token, refresh_jwt_token: load(import) modules for JWT authentication.
  • obtain_jwt_token: it’s used when JWT token issue. 토큰을 발행할 때 사용합니다. (path('api/token/', obtain_jwt_token))
  • verify_jwt_token: it’s for JWT token verification. (path('api/token/verify/', verify_jwt_token))
  • refresh_jwt_token: it’s for refreshing JWT token. (path('api/token/refresh/', refresh_jwt_token))
  • path(‘api/blog/’, include(‘blog.urls’)): this is connect our Blog App URL.

create and modify blog/urls.py like below to create Blog App URL.

from django.urls import path
from . import views

urlpatterns = [
    path('posts/', views.posts, name='posts'),
]

Create View

let’s make API that uses JWT authentication. open blog/views.py and modify it like below.

from django.shortcuts import render
from django.core import serializers
from django.http import HttpResponse
from rest_framework.decorators import api_view, permission_classes, authentication_classes
from rest_framework.permissions import IsAuthenticated
from rest_framework_jwt.authentication import JSONWebTokenAuthentication

from .models import Post


@api_view(['GET'])
@permission_classes((IsAuthenticated, ))
@authentication_classes((JSONWebTokenAuthentication,))
def posts(request):
    posts = Post.objects.filter(
        published_at__isnull=False).order_by('-published_at')
    post_list = serializers.serialize('json', posts)
    return HttpResponse(post_list, content_type="text/json-comment-filtered")

이제까지 만들어 보던 뷰(View)와 많이 다릅니다. 간단히 살펴보도록 하겠습니다.

from django.shortcuts import render
from django.core import serializers
from django.http import HttpResponse
...
from .models import Post
...
def posts(request):
    posts = Post.objects.filter(published_at__isnull=False).order_by('-published_at')
    post_list = serializers.serialize('json', posts)
    return HttpResponse(post_list, content_type="text/json-comment-filtered")

I’ve introduced this part already at the previous blog post(Convert django Models to JSON for response). to convert and response Model data(QuerySet) to JSON. let’s see new lines.

...
from rest_framework.decorators import api_view, permission_classes, authentication_classes
from rest_framework.permissions import IsAuthenticated
from rest_framework_jwt.authentication import JSONWebTokenAuthentication
...
@api_view(['GET'])
@permission_classes((IsAuthenticated, ))
@authentication_classes((JSONWebTokenAuthentication,))
def posts(request):
...
  • from rest_framework.decorators import api_view, permission_classes, authentication_classes: these are python decorator that djangorestframework provides. it takes too much times to introduce python decorator. simply, it’s pretreatment.
  • from rest_framework.permissions import IsAuthenticated: these will be used to check login state
  • from rest_framework_jwt.authentication import JSONWebTokenAuthentication: to be used to check JWT authentication.
  • @api_view(['GET']): this is the decorator we’ve seen above. this will be called before calling below function(def posts(request):). this decorator checks the request is GET or not and if it’s not GET request, it returs JSON type error message.
  • @permission_classes((IsAuthenticated, )): check the permission. in here, just check login(Authenticated) or not.
  • @authentication_classes((JSONWebTokenAuthentication,)): check JWT token. if token is not fine, it returns JSON type error message.

Check

let’s check our working via Postman. execute the command below to start django test server.

python manage.py runserver

and the send GET request to http://localhost:8000/api/blog/posts/ in Postman like below

Use JWT in django - JWT authentication error

we can see the error message like above. we can know our API is protected by JWT authentication.

let’s issue JWT token to get the data. request POST to http://localhost:8000/api/token/ with username and password. in here, username and password are django superuser we’ve created above.(username and password to login django administrator page)

Use JWT in django - issue JWT token

we can see JWT token is issued well like above. let’s request http://localhost:8000/api/blog/posts/ again with JWT token in this time. in this time, we set jwt [jwt key] in Header, Authorization.

Use JWT in django - get the data using JWT token

now, we can get the data! next, let’s see verify and refresh JWT token. send POST request to http://localhost:8000/api/token/verify/ with JWT token for verifying JWT token.

Use JWT in django - verify JWT token

we can see no error like above. if JWT token has problems, you can see the error message like below.

Use JWT in django - JWT token verification error

let’s see how to refresh JWT token. send POST request to http://localhost:8000/api/token/refresh/ with JWT token.

Use JWT in django - refresh JWT token

after then, we can get new JWT token like above. if we don’t refresh JWT token or JWT token is expired, we can see the error message like below.

Use JWT in django - JWT token error

Completed

we’ve seen how to use JWT token in django. now, we can make API server to communicate App or Frontend with JWT token!

Reference

Buy me a coffeeBuy me a coffee
Posts