Authentication
Authentication is the mechanism of associating an incoming request with a set of identifying credentials, such as the user the request came from, or the token that it was signed with.
Built-in Authentication Schemes
DRF provides several built-in authentication schemes out of the box.
BasicAuthentication
The BasicAuthentication scheme uses standard HTTP Basic Authentication, signed against a user's username and password. Basic authentication is generally only appropriate for testing.
request.user: Will be a DjangoUserinstance.request.auth: Will beNone.
WARNING
If you use BasicAuthentication in production, you must ensure that your API is only available over https. API clients should always re-request credentials at login and never store them in persistent storage.
TokenAuthentication
The TokenAuthentication scheme uses a simple token-based HTTP Authentication scheme. This is appropriate for client-server setups, such as native desktop and mobile clients.
request.user: Will be a DjangoUserinstance.request.auth: Will be arest_framework.authtoken.models.Tokeninstance.
WARNING
If you use TokenAuthentication in production, you must ensure that your API is only available over https.
Setup
To use token authentication, configure the authentication classes to include TokenAuthentication, and additionally include rest_framework.authtoken in your INSTALLED_APPS setting:
INSTALLED_APPS = [
# ...
'rest_framework.authtoken'
]
REST_FRAMEWORK = {
'DEFAULT_AUTHENTICATION_CLASSES': [
'rest_framework.authentication.TokenAuthentication',
# ...
]
}Make sure to run manage.py migrate after changing your settings. The rest_framework.authtoken app provides Django database migrations for the token model.
Generating Tokens
There are several ways to generate and obtain tokens for your users.
By exposing an API endpoint
DRF provides a built-in view for clients to obtain a token given a valid username and password. Add the obtain_auth_token view to your URLconf:
from django.urls import path
from rest_framework.authtoken import views
urlpatterns += [
path('api-token-auth/', views.obtain_auth_token)
]When valid username and password fields are POSTed to this view (using form data or JSON), it will return a JSON response:
{ "token": "9944b09199c62bcf9418ad846dd0e4bbdfc6ee4b" }By using signals
If you want every user to have an automatically generated Token, you can catch the User model's post_save signal:
from django.conf import settings
from django.db.models.signals import post_save
from django.dispatch import receiver
from rest_framework.authtoken.models import Token
@receiver(post_save, sender=settings.AUTH_USER_MODEL)
def create_auth_token(sender, instance=None, created=False, **kwargs):
if created:
Token.objects.create(user=instance)(Place this code snippet in an installed models.py module, or some other location that will be imported by Django on startup.)
Using the manage.py command
You can also generate a user token from the command line:
./manage.py drf_create_token <username>This returns the API token for the given user, creating it if it doesn't exist. You can also pass the -r flag to regenerate the token if it has been compromised.
Usage
For clients to authenticate, the token key should be included in the Authorization HTTP header, prefixed by the string literal "Token", with whitespace separating the two strings:
Authorization: Token 9944b09199c62bcf9418ad846dd0e4bbdfc6ee4bIf you want to use a different keyword in the header, such as Bearer, simply subclass TokenAuthentication and set the keyword class variable.
TIP
The built-in token authentication is fairly simple and only supports one token per user. For production applications, consider these popular third-party alternatives:
- Django REST Knox: Uses stateful, opaque tokens with multi-device support to instantly revoke a specific session. Best if you are building a standard monolith and want tight security controls (like showing a "Logged in Devices" page where users can click "Log out of Phone").
- SimpleJWT: Best if you are building a highly scalable microservice architecture, or if you want to minimize database hits on every request using stateless JSON Web Tokens (JWT).
SessionAuthentication
The SessionAuthentication scheme uses Django's default session backend for authentication. This is appropriate for AJAX clients that are running in the same session context as your website.
request.user: Will be a DjangoUserinstance.request.auth: Will beNone.
CSRF Protection
CSRF validation in DRF intentionally exempts anonymous requests to allow stateless authentication methods (like Tokens) to work. This means anonymous requests won't be blocked for missing an X-CSRFToken header. As a result:
- AJAX Clients: Because DRF strictly enforces CSRF validation on session-based authentication, any frontend client making "unsafe" HTTP calls (
PUT,PATCH,POST,DELETE) via sessions must attach a valid CSRF token header, otherwise the request will be rejected. - Login Views: Because anonymous requests bypass CSRF checks, using a standard DRF API view for a login page leaves it vulnerable. Always use standard Django login views to ensure proper protection.
NOTE
SessionAuthentication is the authentication scheme used by the Browsable API and Django's Admin UI, to allow developers to interact with the API while logged in through their browser.
RemoteUserAuthentication
The RemoteUserAuthentication scheme allows you to delegate authentication to your web server (like Apache or NGINX), which sets the REMOTE_USER environment variable.
request.user: Will be a DjangoUserinstance.request.auth: Will beNone.
To use this, you must have django.contrib.auth.backends.RemoteUserBackend (or a subclass) in your AUTHENTICATION_BACKENDS setting.
NOTE
By default, RemoteUserBackend creates User objects for usernames that don't already exist. To change this and other behavior, consult the Django documentation.
Web Server Configuration
Consult your web server's documentation for information about configuring an authentication method, for example:
Setting the Authentication Scheme
By default, if you don't configure anything, DRF uses the following authentication classes:
[
'rest_framework.authentication.SessionAuthentication',
'rest_framework.authentication.BasicAuthentication'
]This means your API can automatically handle Django session-based authentication (useful for the browsable API and AJAX) and standard HTTP Basic Auth right out of the box.
You can override these globally in your settings.py. This keeps your code DRY by applying the same logic across all views.
REST_FRAMEWORK = {
'DEFAULT_AUTHENTICATION_CLASSES': [
'rest_framework.authentication.BasicAuthentication',
'rest_framework.authentication.SessionAuthentication',
'rest_framework.authentication.TokenAuthentication'
]
}Or on a per-view basis:
from rest_framework.authentication import SessionAuthentication, BasicAuthentication
from rest_framework.permissions import IsAuthenticated
from rest_framework.response import Response
from rest_framework.views import APIView
class ExampleView(APIView):
authentication_classes = [SessionAuthentication, BasicAuthentication]
permission_classes = [IsAuthenticated]
def get(self, request, format=None):
content = {
'user': str(request.user), # `django.contrib.auth.User` instance.
'auth': str(request.auth), # None
}
return Response(content)from rest_framework.decorators import api_view, authentication_classes, permission_classes
from rest_framework.authentication import SessionAuthentication, BasicAuthentication
from rest_framework.permissions import IsAuthenticated
from rest_framework.response import Response
@api_view(['GET'])
@authentication_classes([SessionAuthentication, BasicAuthentication])
@permission_classes([IsAuthenticated])
def example_view(request, format=None):
content = {
'user': str(request.user), # `django.contrib.auth.User` instance.
'auth': str(request.auth), # None
}
return Response(content)How Authentication is Determined
Authentication schemes are evaluated in order. DRF tries each class in the list and stops at the first one that successfully authenticates, setting request.user and request.auth accordingly.
If all fail, request.user becomes an AnonymousUser and request.auth is set to None.
Unauthorized Responses
When an unauthenticated request is denied access, the error response depends entirely on the first authentication class defined on the view:
| Primary Auth Scheme | HTTP Status | WWW-Authenticate Header? | Example Header |
|---|---|---|---|
BasicAuthentication | 401 Unauthorized | Yes | Basic realm="api" |
TokenAuthentication | 401 Unauthorized | Yes | Token |
SessionAuthentication | 403 Forbidden | No | - |
RemoteUserAuthentication | 403 Forbidden | No | - |
Custom Authentication
To implement a custom authentication scheme, subclass BaseAuthentication and override the .authenticate(self, request) method.
The method should return a two-tuple of (user, auth) if authentication succeeds, or None otherwise. You may also raise an AuthenticationFailed exception if authentication is attempted but fails.
from django.contrib.auth.models import User
from rest_framework import authentication
from rest_framework import exceptions
class ExampleAuthentication(authentication.BaseAuthentication):
def authenticate(self, request):
username = request.META.get('HTTP_X_USERNAME')
if not username:
return None
try:
user = User.objects.get(username=username)
except User.DoesNotExist:
raise exceptions.AuthenticationFailed('No such user')
return (user, None)Django 5.1+ LoginRequiredMiddleware
Django 5.1 introduced a LoginRequiredMiddleware that forces users to log in before viewing any page.
DRF intentionally ignores this middleware.
If a mobile app or frontend client tries to access an API without logging in, this middleware would try to redirect them to an HTML login page. APIs should return an HTTP 401 Unauthorized error, not a webpage redirect.
TIP
If you want to lock down your entire API so that only logged-in users can use it, ignore the middleware and set DEFAULT_PERMISSION_CLASSES to IsAuthenticated in your DRF settings.py instead.
Apache mod_wsgi Configuration
By default, Apache's mod_wsgi blocks the authorization header, assuming authentication is handled at the server level.
If you are using non-session authentication (like TokenAuthentication or JWTs), you must explicitly allow these headers to reach DRF by adding the following to your server config, virtual host, directory, or .htaccess:
WSGIPassAuthorization OnTIP
If your application requires social login (Google, GitHub, Apple), passwordless auth, or OAuth2, there is a massive ecosystem of Third-Party Packages designed specifically to integrate seamlessly with DRF.
