Evgenii Legotckoi
Evgenii LegotckoiFeb. 14, 2022, 4:24 a.m.

Django Rest Framework - Tutorial 001. Adding Token Authentication

At the moment I am actively working on an application that will work with the REST API of a Django site. And one of the first steps was to set up user authentication by token, but in order for this to work, you must first obtain an authorization token.

Let's look at how this can be done.

Install Django Rest Framework

Since this is the very first article on using DRF, I will describe in more detail the process of installing and configuring DRF. In what follows, I will no longer give these instructions.

Install DRF and other necessary packages

pip install djangorestframework
pip install markdown       # Markdown support for the browsable API.
pip install django-filter

Next, add the application 'rest_frameword' to INSTALLED_APPS in the site configuration file settings.py


Further, the official documentation suggests including the login and logout View from rest_framework in the urls.py file, so that you can conveniently use the API in the browser.

To be honest, I don’t use this API, because it’s more convenient for me to use the documentation generated through swagger, which I will also talk about later, but I still connect the View data so that I don’t solve random problems later.

urlpatterns = [
    path('api-auth/', include('rest_framework.urls')),

Next, configure the default authentication and permission classes (also in settingsp.py)


Now everything is ready in order to write an access point to receive a token. But first I want to connect the generation of swagger documentation. It’s just more convenient to work this way, for example, I really like the redoc documentation, in which everything is displayed quite beautifully and conveniently.

Installing Swagger

And now we will immediately connect swagger on the site. I understand that this is not related to the topic of the article, but in the code I do special manipulations to enable a special documentation display and I think that this may be useful to you in the future, because:

  • You will use swagger in the future
  • You will sometimes need to customize the output of information in the API description, namely for the token I had the most specific change for swagger.

Установим drf-yasg

To do this, following the documentation, run the following command

pip install -U drf-yasg

Then we modify the settings.py file

   'django.contrib.staticfiles',  # required for serving swagger ui's css/js files

And now let's register swagger in the site urls

from django.urls import re_path
from drf_yasg import openapi
from drf_yasg.views import get_schema_view
from rest_framework import permissions

schema_view = get_schema_view(
      title="EXAMPLE API",
      description="REST API Documentation",

urlpatterns = [
    re_path(r'^swagger(?P<format>\.json|\.yaml)$', schema_view.without_ui(cache_timeout=0), name='schema-json'),
    re_path(r'^swagger/$', schema_view.with_ui('swagger', cache_timeout=0), name='schema-swagger-ui'),
    re_path(r'^redoc/$', schema_view.with_ui('redoc', cache_timeout=0), name='schema-redoc'),

If you take a close look at the code, you will see that I registered the swagger only for the administration of the site. If you want the documentation to be open, then remove this line


Optionally, you can add information to the documentation output about which authentication types are used for the API. This is done in the settings.py file.

      'Basic': {
            'type': 'basic'
      'Bearer': {
            'type': 'apiKey',
            'name': 'Authorization',
            'in': 'header'

Now you can start implementing an access point to get a token.

Api application

Let's create an api application in which an endpoint will be added to receive a token.

python manage.py startapp api


Next, we will create a file with serializers, in which a special serializer will be created that will describe the site's response in swagger.

# -*- coding: utf-8 -*-

from rest_framework import serializers

class Response201AuthTokenSerializer(serializers.Serializer):
    token = serializers.CharField(required=True, allow_blank=False)
    user_id = serializers.IntegerField(required=True)

This serializer will correctly generate the response information in the documentation, and I use it to generate a JSON response with a token.


Then we modify the views.py file to get the endpoint.

# -*- coding: utf-8 -*-

from django.contrib.auth import get_user_model
from django.http import JsonResponse
from django.utils.translation import gettext_lazy as _
from drf_yasg import openapi
from drf_yasg.utils import swagger_auto_schema
from rest_framework import authentication, viewsets
from rest_framework.authtoken.views import ObtainAuthToken

from api.serializers import Response201AuthTokenSerializer

class CustomAuthToken(ObtainAuthToken):
    authentication_classes = [authentication.BasicAuthentication]

        "201": openapi.Response(
            description=_("User has got Token"),
    def post(self, request, *args, **kwargs):
        serializer = self.serializer_class(data=request.data,
                                           context={'request': request})
        user = serializer.validated_data['user']
        token, created = Token.objects.get_or_create(user=user)
        response201 = Response201AuthTokenSerializer(data={"token": token.key, "user_id": user.pk})
        return JsonResponse(response201.data)

As you can see in the code there is a custom swagger schema for the 201 response, the content has been created. The correct documentation will be generated from the Response201AuthTokenSerializer serializer.
Among other things, I use the Response201AuthTokenSerializer to form a response with a token as well as a user id. In the future, I use the user id to manipulate data in a mobile application.
A distinctive nuance of this view is that only BasicAuthentication is used as authentication, that is, the user gets access to this view only through username and password. In the future, API development is underway to use the token.


And now connect the view to get the token in the urls files

# -*- coding: utf-8 -*-

from django.urls import path

from api import views

app_name = 'api'
urlpatterns = [
    path('api-token-auth/', views.CustomAuthToken.as_view()),

In this file, we define the name of the application that is used to generate routes, that is, api. We also connect the view of the token to the routing.

And at the end, we include the urls.py of the api application in the main urls.py file of the entire project.

urlpatterns = [
    path('api/', include('api.urls')),

Now, in order to get a token, you need to send a POST request to the url , if you want to test the functionality on a local server. In the case of a combat server, you need to send a request to the address with the domain of your site.

For authentication, you need to use Basic authentication.

Example of token request in Felgo QML

Here is an example code for requesting a token in an application written in QML Felgo

function login(username, password, success, error) {
    .post("", {username: username, password: password})
    .set('Content-Type', 'application/json')
    .then(function(res) { success(res) })
    .catch(function(err) { error(err) });
We recommend hosting TIMEWEB
We recommend hosting TIMEWEB
Stable hosting, on which the social network EVILEG is located. For projects on Django we recommend VDS hosting.

Do you like it? Share on social networks!

  • Feb. 14, 2022, 6:42 a.m.

Доброго времени.
А если кастомный юзер.
И активация юзера подтверждением по смс или звонку?

Evgenii Legotckoi
  • Feb. 14, 2022, 6:54 a.m.
  • (edited)

Добрый день

Если Вы имеетe ввиду, что модель пользователя наследована от AbstractUser и переопределена для проекта, то да - этот пример рабочий, я сейчас занимаюсь одним проектом, который будет иметь приложение и использую там кастомного пользователя.

А что касается подтверждения по СМС, то я участвовал несколько лет назад в проекте, где было подтверждение по СМС. Код показать не могу, но суть была в том, что там было два REST API View, сначало приложение стучалось на первый url, куда посылало логин и пароль, при получении ответа 200, приложение меняло форму ввода данных и ждало, пока пользователь заполнит код из СМС и подтвердит отправку. В этом случае отправка кода была уже на второй url, который проверял правильность кода, и уже в этом случае отдавал токен.

Естественно первый URL, который обрабатывал логин и пароль, стучался на API стороннего провайдера по отправке СМС, получал отправленный код и сохранял в отдельную таблицу, чтобы потом сравнить код и соответствие пользователя коду.

  • Feb. 14, 2022, 7:14 a.m.
  • (edited)

В моем случае кастом от AbstractBaseUser

class User(AbstractBaseUser):
    phone       = PhoneNumberField(region='RU', unique=True)
    username    = models.CharField(max_length = 150, blank = True, null = True)
    standard    = models.CharField(max_length = 3, blank = True, null = True)
    score       = models.IntegerField(default = 16)
    first_login = models.BooleanField(default=False)
    active      = models.BooleanField(default=False)
    staff       = models.BooleanField(default=False)
    admin       = models.BooleanField(default=False)
    timestamp   = models.DateTimeField(auto_now_add=True)

    USERNAME_FIELD = 'phone'

    objects = UserManager()

    def __str__(self):
        return self.phone

    def get_full_name(self):
        return self.phone

    def get_short_name(self):
        return self.phone

    def has_perm(self, perm, obj=None):
        return True

    def has_module_perms(self, app_label):

        return True

    def is_staff(self):
        return self.staff

    def is_admin(self):
        return self.admin

    def is_active(self):
        return self.active

Только токен я использую knox(Стандарт мобильной безопастности Samsung), потому и спросил

Дальше понятно:
Регистрация post на страницу урл api/register(можно сразу отправить запрос на звонок, после создания пользователя)
Если удачно то получим 4-x символьный код от провайдера, запищем его. Если неудачно то создаем свой и шлем смс
Cледом post-запрос на верификацию с кодом(при удаче - активируем пользователя, при не удаче 4 попытки на повтор)

Evgenii Legotckoi
  • Feb. 14, 2022, 7:22 a.m.

В таком случае без напильника этот код сходу не взлетит, если конкретно knox нужно использовать.
А касательно самого AbstractBaseUser, то должно заработать.


Only authorized users can post comments.
Please, Log in or Sign up

Qt - Test 001. Signals and slots

  • Result:57points,
  • Rating points-2

C++ - Test 001. The first program and data types

  • Result:60points,
  • Rating points-1

C++ - Test 005. Structures and Classes

  • Result:0points,
  • Rating points-10
Last comments
JonnyJoJune 8, 2023, 12:14 p.m.
Qt/C++ - Lesson 019. How to paint triangle in Qt5. Positioning shapes in QGraphicsScene Евгений, здравствуйте! Решил поэкспериментировать немного с кодом из этого урока, нарисовать вместо треугольника квадрат и разобраться с координатами. В итоге, запутался. И ни документация,…
JonnyJoMay 25, 2023, 2:24 p.m.
How to make game using Qt - Lesson 2. Animation game hero (2D) Евгений, благодарю!
Evgenii Legotckoi
Evgenii LegotckoiMay 25, 2023, 4:49 a.m.
How to make game using Qt - Lesson 2. Animation game hero (2D) Код на строчка 184-198 вызывает перерисовку области на каждый 4-й такт счётчика. По той логике не нужно перерисовывать объект постоянно, достаточно реже, чем выполняется игровой слот. А слот вып…
JonnyJoMay 21, 2023, 10:49 a.m.
How to make game using Qt - Lesson 2. Animation game hero (2D) Евгений, благодарю! Всё равно не совсем понимаю :( Если муха двигает ножками только при нажатии клавиш перемещение, то что, собственно, делает код со строк 184-198 в triangle.cpp? В этих строчка…
Evgenii Legotckoi
Evgenii LegotckoiMay 21, 2023, 5:57 a.m.
How to make game using Qt - Lesson 2. Animation game hero (2D) Добрый день. slotGameTimer срабатывает по таймеру и при каждой сработке countForSteps увеличивается на 1, это не зависит от нажатия клавиш, нажатая клавиша лишь определяет положение ножек, котор…
Now discuss on the forum
TwangerJune 7, 2023, 11:12 a.m.
Ошибка при выполнении триггерной функции (GreenPlum) Есть 3 таблицы fact_amount со структурой: CREATE TABLE fact_amount ( id serial4 NOT NULL, fdate date NULL, type_activity_id int4 NULL, status_id int4 NULL, CONSTRAINT fact…
Alexander RyabikovJune 6, 2023, 1:35 p.m.
Работа с QFileSystemModel Вопросик по теме QFileSystemModel в Linux. Он, как и положено, обновляется самостоятельно, если директория локальная. Но, вот, сетевая папка (у меня шара samba) не обновляется. Как её можно…
Evgenii Legotckoi
Evgenii LegotckoiApril 16, 2023, 4:07 a.m.
Мобильное приложение на C++Qt и бэкенд к нему на Django Rest Framework Да, это возможно. Но подобные вещи лучше запускать через celery. То есть drf принимает команду, и после этого регистрирует задачу в celery, котроый уже асинхронно всё это выполняет. В противном …
Алексей БобровDec. 14, 2021, 7:03 p.m.
Sorting the added QML elements in the ListModel I am writing an alarm clock in QML, I am required to sort the alarms in ascending order (depending on the date or time (if there are several alarms on the same day). I've done the sorting …

Follow us in social networks