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.Meta):
        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.


Want to learn how to build RESTful APIs with Python and Django? Check out my book REST APIs with Django.