User Registration, Login, Logout API using Django Rest Framework

In this tutorial guide, we’ll explore how to implement user authentication in a Django Rest Framework (DRF) project, covering user registration, login (with both username and email), and logout functionality. Authentication is a crucial aspect of web applications to protect user data and ensure a secure user experience. We’ll use DRF’s powerful tools and features to create a robust authentication system. This tutorial can also be used same as it is with MySQL and Postgres. Let’s get started!

Note: For this tutorial, we are using our basic skeleton project for Django. You can also download the project from here.

Step 1. Setting Up Django Rest Framework

Ensure you have Django and DRF installed. If not, you can install them using pip:

pip install django djangorestframework

Next, create a new Django project and app within the project, we usually recommend “accounts” name for authenticaion app.

django-admin startproject mydrfproject
cd mydrfproject
python manage.py startapp accounts

Add ‘rest_framework’, ‘rest_framework.authtoken’, and ‘accounts’ to the INSTALLED_APPS in “mydrfproject/settings.py”:

INSTALLED_APPS = [
    # ...
    'rest_framework',
    'rest_framework.authtoken',
    'accounts',
    # ...
]

Step 2: Creating the Custom User Model

In “accounts/models.py”, define the custom user model:

# accounts/models.py

from django.contrib.auth.models import AbstractUser
from django.db import models

class CustomUser(AbstractUser):
    email = models.EmailField(unique=True)

    # Add custom fields here, if needed

    def __str__(self):
        return self.username

Update the AUTH_USER_MODEL and REST_FRAMEWORK default authentication classes in “mydrfproject/settings.py”:

AUTH_USER_MODEL = 'accounts.CustomUser'

REST_FRAMEWORK = {
    'DEFAULT_AUTHENTICATION_CLASSES': [
        'rest_framework.authentication.TokenAuthentication',
    ],
    # Other settings...
}

Run migrations to create the custom user model table:

python manage.py makemigrations
python manage.py migrate

Step 3: Serializers for User Authentication

Create serializers.py within the “accounts” app directory:

# accounts/serializers.py

from rest_framework import serializers
from .models import CustomUser

class UserSerializer(serializers.ModelSerializer):
    class Meta:
        model = CustomUser
        fields = ['username', 'email', 'password']
        extra_kwargs = {'password': {'write_only': True}}

    def create(self, validated_data):
        user = CustomUser(
            username=validated_data['username'],
            email=validated_data['email']
        )
        user.set_password(validated_data['password'])
        user.save()
        return user

Step 4: Registering New Users

Create a new API view in “accounts/views.py” for user registration:

# accounts/views.py

from rest_framework import status
from rest_framework.response import Response
from rest_framework.decorators import api_view
from .serializers import UserSerializer

@api_view(['POST'])
def register_user(request):
    if request.method == 'POST':
        serializer = UserSerializer(data=request.data)
        if serializer.is_valid():
            serializer.save()
            return Response(serializer.data, status=status.HTTP_201_CREATED)
        return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)

Step 5: User Login with Authentication Tokens (Username or Email)

In “accounts/views.py”, create a new API view for user login that supports both username and email login:

# accounts/views.py

from rest_framework.authtoken.models import Token
from django.contrib.auth import authenticate
from rest_framework.decorators import api_view
from rest_framework.response import Response
from rest_framework import status
from django.core.exceptions import ObjectDoesNotExist

from .models import CustomUser

@api_view(['POST'])
def user_login(request):
    if request.method == 'POST':
        username = request.data.get('username')
        password = request.data.get('password')

        user = None
        if '@' in username:
            try:
                user = CustomUser.objects.get(email=username)
            except ObjectDoesNotExist:
                pass

        if not user:
            user = authenticate(username=username, password=password)

        if user:
            token, _ = Token.objects.get_or_create(user=user)
            return Response({'token': token.key}, status=status.HTTP_200_OK)

        return Response({'error': 'Invalid credentials'}, status=status.HTTP_401_UNAUTHORIZED)

Step 6: Implementing User Logout

To handle user logout, we’ll create a new API view in “accounts/views.py”:

# accounts/views.py

from rest_framework.authtoken.models import Token
from rest_framework.decorators import api_view, permission_classes
from rest_framework.permissions import IsAuthenticated
from rest_framework.response import Response
from rest_framework import status

@api_view(['POST'])
@permission_classes([IsAuthenticated])
def user_logout(request):
    if request.method == 'POST':
        try:
            # Delete the user's token to logout
            request.user.auth_token.delete()
            return Response({'message': 'Successfully logged out.'}, status=status.HTTP_200_OK)
        except Exception as e:
            return Response({'error': str(e)}, status=status.HTTP_500_INTERNAL_SERVER_ERROR)

Step 7: Wiring Up the URLs

In “accounts/urls.py”, connect the views to URLs:

# accounts/urls.py

from django.urls import path
from .views import register_user, user_login, user_logout

urlpatterns = [
    path('register/', register_user, name='register'),
    path('login/', user_login, name='login'),
    path('logout/', user_logout, name='logout'),
]

Include the “accounts/urls.py” in the project’s main “mydrfproject/urls.py”:

# mydrfproject/urls.py

from django.contrib import admin
from django.urls import path, include

urlpatterns = [
    path('admin/', admin.site.urls),
    path('api/', include('accounts.urls')),  # Include the app's URLs
]

Step 8: Testing the Authentication

To test the authentication endpoints, use cURL or a REST API client like Postman. Here are the example cURL commands:

a. Register a new user:

curl -X POST -H "Content-Type: application/json" -d '{"username": "testuser", "password": "testpassword", "email": "[email protected]"}' http://localhost:8000/api/register/

b. Login with the registered user (using username or email) and get the authentication token:

curl -X POST -H "Content-Type: application/json" -d '{"username": "testuser", "password": "testpassword"}' http://localhost:8000/api/login/

c. Logout using the authentication token:

curl -X POST -H "Authorization: Token YOUR_AUTH_TOKEN" http://localhost:8000/api/logout/

Replace YOUR_AUTH_TOKEN with the actual authentication token obtained during login.

Conclusion

Congratulations! You’ve successfully implemented user registration, login (supporting both username and email), and logout functionality using Django Rest Framework. By leveraging DRF’s powerful features, you’ve created a secure and user-friendly authentication system for your Django application. Remember to thoroughly test your code and follow best practices to ensure a robust and scalable authentication system. You can further enhance the system by implementing features like email verification, password reset, or social authentication.

Find this tutorial on Github.

Next Tutorial: Reset and Change Password in DRF

Blogs You Might Like to Read!