Django Rest Framework User Authentication Tutorial - Custom User Model + Social Auth
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 Desktop
$ 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:
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 ListAPIView.
# users/views.py
from rest_framework import generics
from . import models
from . import serializers
class UserListView(generics.ListAPIView):
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.
Try out login to with an existing account at http://127.0.0.1:8000/api/v1/rest-auth/login/.
And to log out go to http://127.0.0.1:8000/api/v1/rest-auth/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/.
You can now create a new user account, login, logout, and view all users via endpoints.
Next Steps
Want to learn more about Django APIs? I’ve written an entire book on the subject called Django for APIs. The first two chapters are available to read for free.