Authentication is one of the most important aspects of any web application or REST API. Without a secure authentication mechanism, your API is vulnerable to unauthorized access, data leaks, and potential security breaches. Django REST Framework (DRF) provides flexible tools to implement authentication, and depending on your use case, you may choose different strategies.
In this tutorial, we’ll explore three common authentication methods in DRF:
-
Session Authentication – Uses Django’s built-in session management and cookies. Great for traditional web apps or when your frontend is tightly coupled with Django.
-
JWT (JSON Web Token) Authentication – A stateless token-based approach. Popular in modern single-page applications (React, Angular, Vue) and mobile apps.
-
OAuth2 Authentication – An industry-standard protocol used when integrating with third-party apps or when you need fine-grained token scopes.
By the end of this tutorial, you’ll be able to:
-
Set up a Django REST Framework project from scratch
-
Implement Session Authentication for browser and API clients
-
Configure JWT Authentication using
djangorestframework-simplejwt
-
Add OAuth2 Authentication using
django-oauth-toolkit
-
Secure API endpoints so only authenticated users can access them
-
Test each authentication method with tools like Postman or
curl
💡 Choosing the right authentication method depends on your project’s needs:
Use Session Auth if your frontend is Django/Template-based.
Use JWT Auth for stateless APIs with modern SPAs or mobile apps.
Use OAuth2 for integrations, microservices, or when exposing APIs to external clients.
Prerequisites
Before diving into the code, make sure you have the following tools and knowledge in place:
Technical Requirements
-
Python 3.12+ installed on your system
-
Pip for installing Python packages
-
Virtual environment (recommended:
venv
orvirtualenv
) to keep dependencies isolated -
Django 5+ and Django REST Framework (DRF) 3.16+
-
djangorestframework-simplejwt for JWT authentication
-
django-oauth-toolkit for OAuth2 authentication
Basic Knowledge
-
Familiarity with Python programming
-
Basic understanding of Django (models, views, settings)
-
Understanding of REST APIs (endpoints, HTTP methods, status codes)
-
Some exposure to authentication concepts (tokens, sessions, headers)
Tools You’ll Use
-
Postman or
curl
for testing API requests -
Text Editor/IDE such as VS Code, PyCharm, or Sublime Text
-
SQLite (default in Django) – no additional database setup required
With these prerequisites covered, we’re ready to set up our Django project and start building authentication step by step.
Setting Up the Django Project
In this section, we’ll create a new Django project, install the required dependencies, and prepare our environment.
Step 1: Create and Activate a Virtual Environment
It’s always best to work in an isolated Python environment.
# Create a new project folder
mkdir drf_auth_demo && cd drf_auth_demo
# Create virtual environment
python3 -m venv venv
# Activate it
# On macOS/Linux:
source venv/bin/activate
# On Windows:
venv\Scripts\activate
Step 2: Install Django and Required Packages
Now, install Django REST Framework and the authentication libraries we’ll use.
pip install django djangorestframework djangorestframework-simplejwt django-oauth-toolkit
Optional but recommended: install drf-yasg or drf-spectacular if you want auto-generated API docs later.
Step 3: Create a New Django Project
Let’s create a new project named drf_auth_demo
.
django-admin startproject drf_auth_demo .
This creates the Django project structure in the current folder.
Step 4: Create an App for Authentication
We’ll use a dedicated app called accounts
to handle users and authentication logic.
python manage.py startapp accounts
Step 5: Update settings.py
Open drf_auth_demo/settings.py
and add the following changes:
INSTALLED_APPS = [
'django.contrib.admin',
'django.contrib.auth',
'django.contrib.contenttypes',
'django.contrib.sessions',
'django.contrib.messages',
'django.contrib.staticfiles',
# Third-party
'rest_framework',
'oauth2_provider', # for OAuth2
# Local
'accounts',
]
REST_FRAMEWORK = {
'DEFAULT_AUTHENTICATION_CLASSES': [
'rest_framework.authentication.SessionAuthentication', # Session
'rest_framework_simplejwt.authentication.JWTAuthentication', # JWT
'oauth2_provider.contrib.rest_framework.OAuth2Authentication', # OAuth2
],
}
Step 6: Run Initial Migrations
Apply initial migrations to set up the database.
python manage.py migrate
Now your project is ready, with DRF and authentication backends configured.
User Model and Serializer
Django already comes with a powerful built-in User model, which we can use directly for authentication. For this tutorial, we’ll stick with Django’s default User
, but you could extend it later if your project requires custom fields.
Step 1: Create a Serializer for the User
Inside your accounts
app, create a new file accounts/serializers.py
and add the following:
from django.contrib.auth.models import User
from rest_framework import serializers
class UserSerializer(serializers.ModelSerializer):
class Meta:
model = User
# We only expose basic user fields for now
fields = ['id', 'username', 'email', 'is_staff']
This serializer will be useful when returning user details via our API.
Step 2: Create Views for User Registration and Profile
Inside accounts/views.py
, let’s add a simple registration endpoint and a profile view.
from django.contrib.auth.models import User
from rest_framework import generics, permissions
from rest_framework.response import Response
from .serializers import UserSerializer
# User Registration View
class RegisterView(generics.CreateAPIView):
queryset = User.objects.all()
serializer_class = UserSerializer
permission_classes = [permissions.AllowAny]
def perform_create(self, serializer):
# Ensure password is hashed
password = self.request.data.get("password")
user = serializer.save()
if password:
user.set_password(password)
user.save()
# User Profile (requires authentication)
class ProfileView(generics.RetrieveAPIView):
serializer_class = UserSerializer
permission_classes = [permissions.IsAuthenticated]
def get_object(self):
return self.request.user
Here’s what’s happening:
-
RegisterView
: Allows anyone to create a new user account. Passwords are hashed properly. -
ProfileView
: Returns the authenticated user’s details.
Step 3: Define URLs for the Endpoints
Inside accounts/urls.py
(create this file if it doesn’t exist):
from django.urls import path
from .views import RegisterView, ProfileView
urlpatterns = [
path('register/', RegisterView.as_view(), name='register'),
path('profile/', ProfileView.as_view(), name='profile'),
]
Now, include this in the main project drf_auth_demo/urls.py
:
from django.contrib import admin
from django.urls import path, include
urlpatterns = [
path('admin/', admin.site.urls),
path('api/accounts/', include('accounts.urls')),
]
Step 4: Test the User Endpoints
Run the server:
python manage.py runserver
Test with Postman or curl
:
1. Register a new user
curl -X POST http://127.0.0.1:8000/api/accounts/register/ \
-H "Content-Type: application/json" \
-d '{"username":"testuser","email":"[email protected]","password":"testpass123"}'
2. Check profile (requires login/session, will be fully tested later)
curl -X GET http://127.0.0.1:8000/api/accounts/profile/
At this stage, the user registration and profile endpoints are ready, which will integrate seamlessly with Session, JWT, and OAuth 2.0 authentication methods.
Session Authentication
Django’s Session Authentication relies on cookies. When a user logs in, Django stores the session ID in the database and sends a cookie to the client. For subsequent requests, the client includes this cookie, and Django uses it to identify the logged-in user.
This works seamlessly for browser-based apps but can also be used for APIs.
Step 1: Enable Session Authentication in Settings
We already added SessionAuthentication
in settings.py
under REST_FRAMEWORK
. Django’s session middleware is enabled by default, so no further setup is needed here.
Step 2: Add Login and Logout Views
Inside accounts/views.py
, add login and logout endpoints.
from django.contrib.auth import authenticate, login, logout
from rest_framework.views import APIView
from rest_framework import status
class LoginView(APIView):
permission_classes = [permissions.AllowAny]
def post(self, request):
username = request.data.get("username")
password = request.data.get("password")
user = authenticate(request, username=username, password=password)
if user is not None:
login(request, user)
return Response({"message": "Login successful"}, status=status.HTTP_200_OK)
return Response({"error": "Invalid credentials"}, status=status.HTTP_400_BAD_REQUEST)
class LogoutView(APIView):
permission_classes = [permissions.IsAuthenticated]
def post(self, request):
logout(request)
return Response({"message": "Logged out successfully"}, status=status.HTTP_200_OK)
Step 3: Add URLs for Login and Logout
Update accounts/urls.py
:
from .views import RegisterView, ProfileView, LoginView, LogoutView
urlpatterns = [
path('register/', RegisterView.as_view(), name='register'),
path('profile/', ProfileView.as_view(), name='profile'),
path('login/', LoginView.as_view(), name='login'),
path('logout/', LogoutView.as_view(), name='logout'),
]
Step 4: Test Session Authentication
Run the server:
python manage.py runserver
1. Log in and create a session
curl -X POST http://127.0.0.1:8000/api/accounts/login/ \
-H "Content-Type: application/json" \
-d '{"username":"testuser","password":"testpass123"}' \
-c cookies.txt
2. Access profile with session cookie
curl -X GET http://127.0.0.1:8000/api/accounts/profile/ \
-b cookies.txt
3. Log out and invalidate the session
curl -X POST http://127.0.0.1:8000/api/accounts/logout/ \
-b cookies.txt
✅ At this point, you’ve implemented Session Authentication for your DRF API. This is a solid choice if Django templates render your frontend or if cookies are acceptable in your client environment.
JWT Authentication
JWT (JSON Web Token) is a compact and self-contained way of securely transmitting information between parties as a JSON object. With djangorestframework-simplejwt
, we can easily integrate JWT into our DRF project.
Step 1: Install and Configure SimpleJWT
We already installed djangorestframework-simplejwt
earlier. If not, install it now:
pip install --upgrade pip
Update settings.py
to configure JWT:
from datetime import timedelta
SIMPLE_JWT = {
"ACCESS_TOKEN_LIFETIME": timedelta(minutes=30),
"REFRESH_TOKEN_LIFETIME": timedelta(days=1),
"ROTATE_REFRESH_TOKENS": True,
"BLACKLIST_AFTER_ROTATION": True,
"AUTH_HEADER_TYPES": ("Bearer",),
}
Step 2: Add JWT Views
simplejwt
come with built-in views for obtaining, refreshing, and verifying tokens.
In drf_auth_demo/urls.py
, add:
from django.urls import path, include
from rest_framework_simplejwt.views import (
TokenObtainPairView,
TokenRefreshView,
TokenVerifyView,
)
urlpatterns = [
path('admin/', admin.site.urls),
path('api/accounts/', include('accounts.urls')),
# JWT endpoints
path('api/token/', TokenObtainPairView.as_view(), name='token_obtain_pair'),
path('api/token/refresh/', TokenRefreshView.as_view(), name='token_refresh'),
path('api/token/verify/', TokenVerifyView.as_view(), name='token_verify'),
]
Step 3: Test JWT Authentication
1. Obtain an Access and Refresh Token
curl -X POST http://127.0.0.1:8000/api/token/ \
-H "Content-Type: application/json" \
-d '{"username":"testuser","password":"testpass123"}'
Response:
{
"refresh": "eyJ0eXAiOiJKV1QiLCJh... (long string)",
"access": "eyJ0eXAiOiJKV1QiLCJh... (long string)"
}
2. Access Protected Endpoint with Bearer Token
curl -X GET http://127.0.0.1:8000/api/accounts/profile/ \
-H "Authorization: Bearer <ACCESS_TOKEN>"
3. Refresh the Token
curl -X POST http://127.0.0.1:8000/api/token/refresh/ \
-H "Content-Type: application/json" \
-d '{"refresh":"<REFRESH_TOKEN>"}'
4. Verify Token
curl -X POST http://127.0.0.1:8000/api/token/verify/ \
-H "Content-Type: application/json" \
-d '{"token":"<ACCESS_TOKEN>"}'
✅ Now your API supports JWT Authentication. Clients can log in once, get a token, and then use that token in the Authorization
header for all future requests.
OAuth2 Authentication
We’ll use django-oauth-toolkit (DOT), which is the go-to package for adding OAuth2 support to Django REST Framework.
Step 1: Install and Add to INSTALLED_APPS
If you haven’t already, install it:
pip install django-oauth-toolkit
In settings.py
, we already added it earlier, but just to confirm:
INSTALLED_APPS += [
'oauth2_provider',
]
Also update REST Framework authentication classes (we already did in Section 3, but here’s the relevant part):
REST_FRAMEWORK = {
'DEFAULT_AUTHENTICATION_CLASSES': [
'rest_framework.authentication.SessionAuthentication',
'rest_framework_simplejwt.authentication.JWTAuthentication',
'oauth2_provider.contrib.rest_framework.OAuth2Authentication',
],
}
Step 2: Add OAuth2 URLs
In drf_auth_demo/urls.py
, include the OAuth2 endpoints:
urlpatterns = [
path('admin/', admin.site.urls),
path('api/accounts/', include('accounts.urls')),
# JWT
path('api/token/', TokenObtainPairView.as_view(), name='token_obtain_pair'),
path('api/token/refresh/', TokenRefreshView.as_view(), name='token_refresh'),
path('api/token/verify/', TokenVerifyView.as_view(), name='token_verify'),
# OAuth2
path('o/', include('oauth2_provider.urls', namespace='oauth2_provider')),
]
This automatically adds endpoints like:
-
/o/applications/
– manage OAuth2 clients -
/o/token/
– obtain tokens -
/o/revoke_token/
– revoke tokens
Step 3: Apply Migrations
Run:
python manage.py migrate
Step 4: Create an OAuth2 Application
Run the dev server and log in to the admin panel:
python manage.py createsuperuser
python manage.py runserver
Go to http://127.0.0.1:8000/admin → Applications (under OAuth2 Provider) → Add Application.
Fill in the fields:
-
Name: MyAppClient
-
Client Type: Confidential
-
Authorization Grant Type: Resource owner password-based
-
Redirect URIs: (leave blank for password grant)
Save it, and copy the Client ID and Client Secret.
Step 5: Obtain an OAuth2 Token
Now, request a token using the Password Grant:
curl -X POST http://127.0.0.1:8000/o/token/ \
-d "grant_type=password" \
-d "username=testuser" \
-d "password=testpass123" \
-d "client_id=lDu3WFYW10NOc1AdG3L2Mmh6JJtCZu41cTSx82LR" \
-d "client_secret=7yvXRV4NKGly4qOTiBptMmLCDQSzzmTKjnY0CGv3NX6ucpA58pxBTqzLSFHCmbJLqMVaa12mqFzxdGJCEaZpBKINo8nd63FZlZ7fPFxFS2nAsjaVVA9cUceiAmT0TVse"
Response:
{
"access_token": "2YotnFZFEjr1zCsicMWpAA...",
"expires_in": 36000,
"token_type": "Bearer",
"scope": "read write",
"refresh_token": "tGzv3JOkF0XG5Qx2TlKWIA..."
}
Step 6: Access Protected Endpoint with OAuth2 Token
curl -X GET http://127.0.0.1:8000/api/accounts/profile/ \
-H "Authorization: Bearer <ACCESS_TOKEN>"
✅ Your API now supports OAuth2 Authentication! 🎉
Protecting API Endpoints
At this point, we have three authentication methods configured. Now, let’s see how to restrict access to certain endpoints so only authenticated users can use them.
Step 1: Apply DRF Permissions
Django REST Framework provides several permission classes. The most common is IsAuthenticated
, which ensures the request is made by a logged-in or valid-token user.
In accounts/views.py
, we already used:
from rest_framework import permissions
class ProfileView(generics.RetrieveAPIView):
serializer_class = UserSerializer
permission_classes = [permissions.IsAuthenticated]
def get_object(self):
return self.request.user
This means:
-
With Session Auth → user must be logged in via
/login/
. -
With JWT Auth → client must provide
Authorization: Bearer <ACCESS_TOKEN>
. -
With OAuth2 Auth → client must provide
Authorization: Bearer <OAUTH2_ACCESS_TOKEN>
.
Step 2: Custom Permissions (Optional)
You can create more fine-grained permissions. For example, only staff users can view all users:
from rest_framework.permissions import BasePermission
class IsAdminUser(BasePermission):
def has_permission(self, request, view):
return request.user and request.user.is_staff
Then apply it:
class UserListView(generics.ListAPIView):
queryset = User.objects.all()
serializer_class = UserSerializer
permission_classes = [IsAdminUser]
Step 3: Test Each Authentication Method
-
Session Authentication
-
Log in via
/api/accounts/login/
(cookie stored). -
Access
/api/accounts/profile/
with saved session cookie → ✅ Success.
-
-
JWT Authentication
-
Obtain a token from
/api/token/
. -
Access
/api/accounts/profile/
withAuthorization: Bearer <ACCESS_TOKEN>
→ ✅ Success.
-
-
OAuth2 Authentication
-
Obtain a token from
/o/token/
. -
Access
/api/accounts/profile/
withAuthorization: Bearer <ACCESS_TOKEN>
→ ✅ Success.
-
If you try without authentication, DRF will return:
{"detail": "Authentication credentials were not provided."}
✅ Now your API endpoints are protected by all three authentication methods. You can choose which one fits your project best or support multiple at the same time.
Testing the Authentication Methods
In this section, we’ll simulate API requests for Session, JWT, and OAuth2 authentication using curl
. You can also test these with Postman.
1. Session Authentication
-
Log in and store the session cookie
curl -X POST http://127.0.0.1:8000/api/accounts/login/ \
-H "Content-Type: application/json" \
-d '{"username":"testuser","password":"testpass123"}' \
-c cookies.txt
-
The
-c cookies.txt
option saves the session cookie.
-
Access the protected endpoint using the session
curl -X GET http://127.0.0.1:8000/api/accounts/profile/ \
-b cookies.txt
-
You should see your user details returned.
-
Logout and invalidate session
curl -X POST http://127.0.0.1:8000/api/accounts/logout/ \
-b cookies.txt
2. JWT Authentication
-
Obtain JWT token
curl -X POST http://127.0.0.1:8000/api/token/ \
-H "Content-Type: application/json" \
-d '{"username":"testuser","password":"testpass123"}'
-
Response includes
access
andrefresh
tokens.
-
Access protected endpoint using JWT
curl -X GET http://127.0.0.1:8000/api/accounts/profile/ \
-H "Authorization: Bearer <ACCESS_TOKEN>"
-
Refresh the JWT token
curl -X POST http://127.0.0.1:8000/api/token/refresh/ \
-H "Content-Type: application/json" \
-d '{"refresh":"<REFRESH_TOKEN>"}'
3. OAuth2 Authentication
-
Obtain an OAuth2 token (Password Grant)
curl -X POST http://127.0.0.1:8000/o/token/ \
-d "grant_type=password" \
-d "username=testuser" \
-d "password=testpass123" \
-d "client_id=<CLIENT_ID>" \
-d "client_secret=<CLIENT_SECRET>"
-
Response includes
access_token
andrefresh_token
.
-
Access protected endpoint using an OAuth2 token
curl -X GET http://127.0.0.1:8000/api/accounts/profile/ \
-H "Authorization: Bearer <ACCESS_TOKEN>"
4. Observations
Method | Storage | Token Expiration | Ideal Use Case |
---|---|---|---|
Session | Cookies | Server-controlled | Traditional web apps |
JWT | Client-side | Configurable (SIMPLE_JWT ) |
SPAs, mobile apps |
OAuth2 | Client-side | Configurable |
Third-party integrations, API marketplaces |
💡 Tip: You can support multiple authentication methods simultaneously, as DRF will try them in order until one succeeds.
✅ With these tests, your readers can verify each authentication method works as intended and understand the differences in flow.
Conclusion + Best Practices
In this tutorial, we explored three authentication methods for Django REST Framework: Session Authentication, JWT Authentication, and OAuth2 Authentication. You now know how to implement, test, and secure your APIs using each method.
Key Takeaways
-
Session Authentication
-
Uses Django’s built-in session and cookie mechanisms.
-
Best for traditional server-rendered web apps.
-
Automatically handles CSRF protection.
-
-
JWT Authentication
-
Stateless and works well for SPAs and mobile clients.
-
Tokens contain user info and can be verified without querying the database.
-
Requires careful handling of token expiration and storage on the client.
-
-
OAuth2 Authentication
-
Industry-standard for secure delegated access.
-
Supports multiple grant types (Password, Client Credentials, Authorization Code).
-
Ideal for third-party integrations and microservices.
-
Best Practices
-
Always use HTTPS – Never transmit tokens or credentials over plain HTTP.
-
Set appropriate token lifetimes – Short-lived access tokens reduce risk if leaked.
-
Use refresh tokens securely – Store them safely and rotate them if possible.
-
Apply proper permissions – Always protect endpoints with
IsAuthenticated
or custom permissions. -
Combine authentication methods wisely – You can support multiple methods, but be clear about which clients use which method.
-
Log out users properly – Invalidate sessions or tokens when necessary.
By following this guide, you now have a flexible, secure, and fully tested authentication system for your Django REST Framework APIs, ready for production or integration with SPAs, mobile apps, or third-party clients.
✅ Next steps: Consider integrating frontend frameworks (React, Angular, Vue) or mobile clients to see how these authentication methods work in real-world scenarios.
You can find the full source code on our GitHub.
=====That's just the basics. If you need more deep learning about Python and the frameworks, you can take the following cheap course:
-
Edureka's Django course helps you gain expertise in Django REST framework, Django Models, Django AJAX, Django jQuery etc. You'll master Django web framework while working on real-time use cases and receive Django certification at the end of the course.
-
Unlock your coding potential with Python Certification Training. Avail Flat 25% OFF, coupon code: TECHIE25
-
Database Programming with Python
-
Python Programming: Build a Recommendation Engine in Django
-
Python Course:Learn Python By building Games in Python.
-
Learn API development with Fast API + MySQL in Python
-
Learn Flask, A web Development Framework of Python
Thanks!