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?