Adding Authentication to a REST Framework Django API

  • 2020-03-10 08:16 AM
  • 209

In this Django REST Framework tutorial, we'll be adding user authentication to an already existing REST API.

This is a continuation of a previous article where we built a simple Bookstore Django REST API with just one endpoint that sends a response {"message": "Welcome to the BookStore!"}.
Want to Create a simple REST API with Django?

At the end of this article,

  • User can register
  • User can log in
  • TokenBased Authentication
  • User can Logout

Let’s get started 😀

First, change directory into the project and spin up our environment:

$ cd bookstore
$ pipenv shell

Now, let’s add some packages to our environment that will handle our authentication:

$ pipenv install django-rest-auth django-allauth

We’ve added some new packages, let’s make our Django app aware of these authentication packages and add some functionalities too. To do this,

# ./bookstore_app/settings.py
...
INSTALLED_APPS = [
    ...
    'rest_framework.authtoken',
    'rest_auth',
    'django.contrib.sites',
    'allauth',
    'allauth.account',
    'rest_auth.registration',
]

Because Django tries to send an email e.g when a user creates an email account, we need to add a little config EMAIL_BACKEND and SITE_ID to the settings.py file. This prints the email to be sent to the console.

# ./bookstore_app/settings.py
...
INSTALLED_APPS = [
    ...
]

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

MIDDLEWARE = [
    ...
]

...

Next, we’ll add the URLs from the rest_auth package to the project’s urls.py file. This gives us access to a host of auth functionalities.

  • User Registration - registration/
  • User Login - login/
  • User Logout - logout/
  • User Details - user/
  • Change Password - password/change/
  • Password Reset - password/reset/
  • Confirm Password Reset - password/reset/confirm/
# ./bookstore_app/urls.py

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

After adding the URLs, let’s now set some Authentication Scheme and
Permission Policies. What file are we going to be setting these?? 🤔

NICE!!! That will be the settings.py file. Thank you for thinking about it for me. 😊

# ./bookstore_app/settings.py
...

REST_FRAMEWORK = {
    # Authentication Scheme
    'DEFAULT_AUTHENTICATION_CLASSES': (
        'rest_framework.authentication.BasicAuthentication',
        'rest_framework.authentication.SessionAuthentication',
        'rest_framework.authentication.TokenAuthentication',
    ),
    # Permission Policies
    'DEFAULT_PERMISSION_CLASSES': [
        'rest_framework.permissions.IsAuthenticated',
    ]
}

Now, let’s run our migrations:

$ python manage.py migrate

Let’s add some restrictions to the welcome viewset in the views.py file so that unauthorized users would not have access.

# ./bookstore_app/api/views.py

from rest_framework.decorators import api_view, permission_classes
from rest_framework.permissions import IsAuthenticated
from django.http import JsonResponse
from django.views.decorators.csrf import csrf_exempt

@api_view(["GET"])
@csrf_exempt
@permission_classes([IsAuthenticated])  
def welcome(request):
    content = {"message": "Welcome to the BookStore!"}
    return JsonResponse(content)

Finally, the restriction is set and an unauthenticated user cannot have access.

Now, let’s test our endpoints. We’ll create a user, log in and access the welcome endpoint. You can use Postman to test with the same JSON properties, but I’ll be using curl.

Registration
> Request

$ curl -X POST -H "Content-Type: application/json" -d '{"username":"testuser", "password1":"testpassword", "password2":"testpassword"}' localhost:8000/registration/

> Response:
   {"key":"1565c60a136420bc733b10c4a165e07698014acb"}

Creating a user and Logging in returns a token that can be used to uniquely identify a user so we’ll skip login and use the token to access the welcome endpoint that we added the restriction to.

Welcome endpoint with Token
> Request
$ curl -X GET -H 'Authorization: Token 1565c60a136420bc733b10c4a165e07698014acb' localhost:8000/api/welcome

> Response
   {"message": "Welcome AH_Bookstore App!"}

Welcome endpoint without Token
> Request
$ curl -X GET -H '' localhost:8000/api/welcome

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

Finally, our authentication works fine. Next, we’ll be adding CRUD functionality to our app and creating some models.

Thank you for reading. 😊

Suggest