DEV Community

Cover image for Django: User Authentication using knox
bhuma08
bhuma08

Posted on • Edited on

Django: User Authentication using knox

To get started, make sure you have django installed by using the command pipenv install django in your terminal. (Make sure you are in a virtual environment: pipenv shell)

Create a project django-admin startproject <project-name>. For this example, I will be creating a project about tvshows! So, my command will be django-admin startproject tvshows.

Now, cd into your project and make sure manage.py is in your root directory.

The command python manage.py runserver allows your app to be up and running. http://127.0.0.1:8000/ on your browser, should show this:

Next, create a superuser:python manage.py createsuperuser
This asks for a username, password and email address. Now that you have created a superuser, on the browser, add /admin to your initial site like this: http://127.0.0.1:8000/admin and your browser should show:

Use the username and password used to create the superuser to login! you should then see:

Now, you are ready to create user auth using knox where a token is generated for a user to login and access data.
You need to install the following:
pipenv install djangorestframework
pipenv install django-rest-knox

In settings.py, add:



INSTALLED_APPS = [
    ...
    'rest_framework',
    'knox'
]


Enter fullscreen mode Exit fullscreen mode

Now, let's create an app for our project.
Use python manage.py startapp <name> in the terminal. For now, I've used python manage.py startapp backend.

Your files in your code editor should look something like this:

Starting with Registration API:

In the backend folder, create a new file and name it serializers.py and add:



from rest_framework import serializers
from django.contrib.auth.models import User
from django.contrib.auth import authenticate

class CreateUserSerializer(serializers.ModelSerializer):
    class Meta:
        model = User
        fields = ('id', 'username', 'password')
        extra_kwargs = {'password': {'write_only': True}}

    def create(self, validated_data):
        user = User.objects.create_user(validated_data['username'],
                                        None,
                                        validated_data['password'])
        return user

class UserSerializer(serializers.ModelSerializer):
    class Meta:
        model = User
        fields = ('id', 'username')


Enter fullscreen mode Exit fullscreen mode

Then, create an api.py file in the backend folder and add:



from rest_framework import viewsets, permissions, generics
from rest_framework.response import Response
from knox.models import AuthToken
from .serializers import CreateUserSerializer, UserSerializer

class RegistrationAPI(generics.GenericAPIView):
    serializer_class = CreateUserSerializer

    def post(self, request, *args, **kwargs):
        serializer = self.get_serializer(data=request.data)
        serializer.is_valid(raise_exception=True)
        user = serializer.save()
        return Response({
            "user": UserSerializer(user, context=self.get_serializer_context()).data,
            "token": AuthToken.objects.create(user)[1]
        })


Enter fullscreen mode Exit fullscreen mode

Now, to add the endpoints, create a urls.py file in the backend folder and add:



from django.urls import path
from .api import RegistrationAPI
from knox import views as knox_views

urlpatterns = [
    path('register/', RegistrationAPI.as_view()),
]


Enter fullscreen mode Exit fullscreen mode

You also need to add endpoint in urls.py file in the project folder which is tvshows in this case:



from django.contrib import admin
from django.urls import path, include

urlpatterns = [
    path('admin/', admin.site.urls),
    path('api/', include('backend.urls')),
    path('api/auth/', include('knox.urls'))
]


Enter fullscreen mode Exit fullscreen mode

Registration API is now complete. Next is creating a Login API.

In the serializers.py in your backend folder, add:



class LoginUserSerializer(serializers.Serializer):
    username = serializers.CharField()
    password = serializers.CharField()

    def validate(self, data):
        user = authenticate(**data)
        if user and user.is_active:
            return user
        raise serializers.ValidationError("Invalid Details.")


Enter fullscreen mode Exit fullscreen mode

Next, in api.py add:



from .serializers import CreateUserSerializer, UserSerializer, LoginUserSerializer

class LoginAPI(generics.GenericAPIView):
    serializer_class = LoginUserSerializer

    def post(self, request, *args, **kwargs):
        serializer = self.get_serializer(data=request.data)
        serializer.is_valid(raise_exception=True)
        user = serializer.validated_data
        return Response({
            "user": UserSerializer(user, context=self.get_serializer_context()).data,
            "token": AuthToken.objects.create(user)[1]
        })


Enter fullscreen mode Exit fullscreen mode

You need to add the endpoints in urls.py in the backend folder:



from .api import RegistrationAPI, LoginAPI

urlpatterns = [
    ...,
    path('login/', LoginAPI.as_view()),
]


Enter fullscreen mode Exit fullscreen mode

Finally, you need an API to shows the user data when the user successfully logs in. To do this, you need to create a class in api.py file in your backend folder:



class UserAPI(generics.RetrieveAPIView):
    permission_classes = [permissions.IsAuthenticated, ]
    serializer_class = UserSerializer

    def get_object(self):
        return self.request.user


Enter fullscreen mode Exit fullscreen mode

This needs an endpoint too. Therefore, in your urls.py in your backend folder, add:



from django.urls import path
from .api import RegistrationAPI, LoginAPI, UserAPI
from knox import views as knox_views

urlpatterns = [
    path('register/', RegistrationAPI.as_view()),
    path('login/', LoginAPI.as_view()),
    path('user/', UserAPI.as_view()),
]


Enter fullscreen mode Exit fullscreen mode

Now, you're all set. Make sure you run those migrations, using python manage.py makemigrations followed by python manage.py migrate.

You can use Postman to check if your endpoint work and you're able to do GET and POST requests.

Let's start with registration. You need to add header and a body to create a new user. So using the url http://127.0.0.1:8000/api/register/, add key Content-Type and value application/json on the header like this:

And add the body to POST to the API, like this:

Your registration has been successful!

You can now log in using http://127.0.0.1:8000/api/login/ and POST method adding the same body used to register. This generates a token:

You cannot access the user details without passing the token that was generated when successfully logging in, as seen below:

You are unable to view the user detail.

Therefore, you need to pass the token like this:

You are now able to view the user detail:

You can also see if the user was successfully created on django admin:

bhuma08 was the superuser I created at the beginning and user1 was created using Postman.

For logout functionality, just add a path in your backend/urls.py:



urlpatterns = [
    ...
    path('logout/', knox_views.LogoutView.as_view(), name='knox_logout')
]


Enter fullscreen mode Exit fullscreen mode

That's the end! :)

Top comments (9)

Collapse
 
nt242298 profile image
Nishant Singh

One problem i am having is that for every login session , knox is creating a new token and this is making my every api to get slow , because now every api is taking lot of time from 600k token entries to identify the one needed for current session.

Is there a way to assign one token with one user , so that this multiple token to one user probelm can get solved.

Also i want that concurrenly multiple user can login with same credentials

Collapse
 
greg_puaczapeta_0a33bf8a profile image
Greg Puac Zapeta

Great post. For some reason I can't get the token in / user /. Any ideas?

Collapse
 
fatmaitstcc profile image
Fatma

in your project settings.py file add

REST_FRAMEWORK = {
'DEFAULT_AUTHENTICATION_CLASSES': ('knox.auth.TokenAuthentication',)
}

Collapse
 
aayodejii profile image
Ayodejii

Thank you. The user endpoint will not work as expected if you don't include this in your settings.py file

Collapse
 
grand_eric profile image
Eric Noel • Edited

token is created in model AuthToken. /user/ from UserAPI , shows only your response is from User model.
Anyway, if you try to get it from AuthToken, you need to decrypt it.

Collapse
 
inaju profile image
mitchel inaju

Thank You so much for writing this article

Collapse
 
geokal profile image
Giorgos Kalpaktsoglou

very nice and short !!!!

Collapse
 
cutecoder2 profile image
Raims pires

how do you get the token expirering date ?

Collapse
 
pranis_h profile image
pranish

While i trying to logout using knox logout url it shows response like this..How to solve..?

{
"detail": "Authentication credentials were not provided."
}