Skip to content

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 Django User instance.
  • request.auth: Will be None.

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 Django User instance.
  • request.auth: Will be a rest_framework.authtoken.models.Token instance.

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:

python
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:

python
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:

json
{ "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:

python
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:

bash
./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:

http
Authorization: Token 9944b09199c62bcf9418ad846dd0e4bbdfc6ee4b

If 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 Django User instance.
  • request.auth: Will be None.

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 Django User instance.
  • request.auth: Will be None.

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:

python
[
    '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.

python
REST_FRAMEWORK = {
    'DEFAULT_AUTHENTICATION_CLASSES': [
        'rest_framework.authentication.BasicAuthentication',
        'rest_framework.authentication.SessionAuthentication',
        'rest_framework.authentication.TokenAuthentication'
    ]
}

Or on a per-view basis:

python
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)
python
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 SchemeHTTP StatusWWW-Authenticate Header?Example Header
BasicAuthentication401 UnauthorizedYesBasic realm="api"
TokenAuthentication401 UnauthorizedYesToken
SessionAuthentication403 ForbiddenNo-
RemoteUserAuthentication403 ForbiddenNo-

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.

python
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:

apache
WSGIPassAuthorization On

TIP

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.