Django Rest Framework is the most popular way to turn a Django website into a modern, robust API. However when it comes time to add user authentication, the official documentation offer a dizzying array of choices.

In this tutorial we will build from scratch a Django API with token-based user authentication. It has a custom user model and uses django-allauth so that we can easily add social authentication via Gmail, Facebook, etc at a later date.

I’ve open-sourced this code as DRFx on Github.

Getting Started

This tutorial assumes you already have Python 3.6x and Pipenv installed. If not, complete instructions can be found here.

First make a new directory for our code, install django, and start a new pipenv shell. Then create a new project called drfx and a new app users.

$ cd Destkop
$ mkdir drfx && cd drfx
$ pipenv install django
$ pipenv shell
(drfx) $ django-admin startproject drfx .
(drfx) $ python manage.py startapp users

The users app will have the code for our custom user model. You should start every new Django project with a custom user model since it gives you the opportunity to make changes in the future. The official documentation even says so.

Since we created a new app let’s add it to our INSTALLED_APPS setting and also signify we’ll be using a custom user model called CustomUser rather than the default User model.

# drfx/settings.py
INSTALLED_APPS = [
  ...
  'users',
]

AUTH_USER_MODEL = 'users.CustomUser'

Next create our model which will have an additional name field since this is more global-friendly than the last name/first name on the default User model.

# users/models.py
from django.contrib.auth.models import AbstractUser
from django.db import models

class CustomUser(AbstractUser):
    name = models.CharField(blank=True, max_length=255)

    def __str__(self):
        return self.email

Create a new users/forms.py file and add the following code. This allows us to make/modify users from the admin app and also within our project itself.

# users/forms.py
from django import forms
from django.contrib.auth.forms import UserCreationForm, UserChangeForm
from .models import CustomUser

class CustomUserCreationForm(UserCreationForm):

    class Meta(UserCreationForm):
        model = CustomUser
        fields = ('username', 'email')

class CustomUserChangeForm(UserChangeForm):

    class Meta:
        model = CustomUser
        fields = UserChangeForm.Meta.fields

Finally update the admin.py file so we can see/use our new CustomUser model and related forms rather than Django’s defaults.

# users/admin.py
from django.contrib import admin
from django.contrib.auth import get_user_model
from django.contrib.auth.admin import UserAdmin

from .forms import CustomUserCreationForm, CustomUserChangeForm
from .models import CustomUser

class CustomUserAdmin(UserAdmin):
    add_form = CustomUserCreationForm
    form = CustomUserChangeForm
    model = CustomUser
    list_display = ['email', 'username', 'name']

admin.site.register(CustomUser, CustomUserAdmin)

Ok, our custom user model is done! Now for the first time run our migrations and create the initial database. Then create a new superuser account and start the local server with runserver so we can login to the admin.

(drf-rest-auth) $ python manage.py makemigrations
(drf-rest-auth) $ python manage.py migrate
(drf-rest-auth) $ python manage.py createsuperuser
(drf-rest-auth) $ python manage.py runserver

Login to the admin panel at http://127.0.0.1:8000/admin with the new superuser account. Click on users and add a new one that we’ll use for testing shortly. I’ve named mine testuser.

Add DRF

Now we can add Django Rest Framework as well as django-rest-auth which is a very convenient third-party package providing API endpoints for user registration, login/logout, password change/reset, social auth, and more. We’ll also create an api app to expose our project’s endpoints.

(drfx) $ pipenv install djangorestframework
(drfx) $ pipenv install django-rest-auth
(drfx) $ python manage.py startapp api

Add the following settings to INSTALLED_APPS.

# drfx/settings.py
INSTALLED_APPS = [
    ...
    'rest_framework',
    'rest_framework.authtoken',
    'rest_auth',

    'api',
    'users',
]

It’s always a good idea to version your APIs so we’ll set the route as api/v1/ for our api app.

# drfx/urls.py
from django.contrib import admin
from django.urls import include, path


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

Within the api app we’ll create a single endpoint that lists all users at users/ and also include rest-auth’s routes. Create a new file called api/urls.py.

# api/urls.py
from django.urls import include, path

urlpatterns = [
    path('users/', include('users.urls')),
    path('rest-auth/', include('rest_auth.urls')),
]

We need our own serializer and view to display all existing users. Create a new file called users/serializers.py and update it as follows.

# users/serializers.py
from rest_framework import serializers
from . import models

class UserSerializer(serializers.ModelSerializer):
    class Meta:
        model = models.CustomUser
        fields = ('email', 'username', )

The views.py file uses DRF’s generic ListCreateAPIView.

# users/views.py
from rest_framework import generics

from . import models
from . import serializers

class UserListView(generics.ListCreateAPIView):
    queryset = models.CustomUser.objects.all()
    serializer_class = serializers.UserSerializer

And we need a urls.py file too.

(drf-rest-auth) $ touch users/urls.py

Then update it to display UserListView.

# users/urls.py
from django.urls import include, path

from . import views

urlpatterns = [
    path('', views.UserListView.as_view()),
]

Finally we can migrate our new changes and then try them out.

(drfx) $ python manage.py migrate

If you go to the users endpoint at http://127.0.0.1:8000/api/v1/users/ you should see the following for your superuser and test user accounts.

Users

Try out login to with an existing account at http://127.0.0.1:8000/api/v1/rest-auth/login/.

Login

And to log out go to http://127.0.0.1:8000/api/v1/rest-auth/logout/.

Logout

Django-allauth

By adding the django-allauth package we can also enable user registration as well as social authentication. The first step is to install the package.

(drfx) $ pipenv install django-allauth

The update our INSTALLED_APPS setting. Make sure to also include an EMAIL_BACKEND and a SITE_ID at the bottom of the settings.py file.

# drfx/settings.py
INSTALLED_APPS = [
    ...

    'rest_framework',
    'rest_framework.authtoken',
    'rest_auth',
    'django.contrib.sites',
    'allauth',
    'allauth.account',
    'rest_auth.registration',

    'api',
    'users',
]

EMAIL_BACKEND = 'django.core.mail.backends.console.EmailBackend'

SITE_ID = 1

We’ve added new apps so it’s time to update the database.

(drfx) $ python manage.py migrate

The final step is to add a URL for registration to the urls.py file.

# api/urls.py
from django.urls import include, path

urlpatterns = [
    path('rest-auth/', include('rest_auth.urls')),
    path('rest-auth/registration/', include('rest_auth.registration.urls')),
]

Ok, we’re done! Make sure the local server is running.

(drf) $ python manage.py runserver

Then navigate to our new user registration page at http://127.0.0.1:8000/api/v1/rest-auth/registration/.

Register

You can now create a new user account, login, logout, and view all users via endpoints.




Interested in learning more Django? I’ve written 3 books!