DEV Community

Cover image for Adding Authentication to a REST Framework Django API
Noble Obioma
Noble Obioma

Posted on

Adding Authentication to a REST Framework Django API

In this article, 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
Enter fullscreen mode Exit fullscreen mode

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

$ pipenv install django-rest-auth django-allauth
Enter fullscreen mode Exit fullscreen mode

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',
]
Enter fullscreen mode Exit fullscreen mode

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 = [
    ...
]

...
Enter fullscreen mode Exit fullscreen mode

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')),
]
Enter fullscreen mode Exit fullscreen mode

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',
    ]
}

Enter fullscreen mode Exit fullscreen mode

Now, let's run our migrations:

$ python manage.py migrate
Enter fullscreen mode Exit fullscreen mode

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)
Enter fullscreen mode Exit fullscreen mode

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/
Enter fullscreen mode Exit fullscreen mode
> Response:
   {"key":"1565c60a136420bc733b10c4a165e07698014acb"}
Enter fullscreen mode Exit fullscreen mode

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
Enter fullscreen mode Exit fullscreen mode
> Response
   {"message": "Welcome AH_Bookstore App!"}
Enter fullscreen mode Exit fullscreen mode
Welcome endpoint without Token
> Request
$ curl -X GET -H '' localhost:8000/api/welcome
Enter fullscreen mode Exit fullscreen mode
> Response
   {"detail":"Authentication credentials were not provided."}
Enter fullscreen mode Exit fullscreen mode

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

Thank you for reading. ๐Ÿ˜Š

Top comments (3)

Collapse
 
aliplutus profile image
aliplutus

I know how to make a modle that only authenticated users can do GET req for it, but how to make a modle and a view where only the users who creatrd it can make GET req to it or the users that i dpesify

Collapse
 
nobleobioma profile image
Noble Obioma

You can create a middleware. These are python classes that hooks into the request/response life cycle and are processed upon every request/response your Django application handles. In then you can have the logic which ascertains that the request made meets the requirements in order to receive a response.

Collapse
 
biorazor profile image
BioRazor

Hey Noble, nice post. Have you faced the need to make custom serializers, according to a custom user model? How have you solved it?