Django REST API – Authentication
In this post, we will protect our Django REST API by adding authentication.
Authentication allows the API to identify who is making a request and decide whether that client should be allowed to access protected resources.
What is authentication?
Authentication is the process of identifying who is making a request.
In a normal Django website, users usually authenticate by logging in with a username and password through a form.
In a REST API, authentication can work in different ways depending on the type of client.
Web browser
React application
Mobile application
Another backend service
External API client
The goal is always the same: the server needs to know who is making the request.
Authentication vs permissions
Authentication and permissions are related, but they are not the same thing.
Authentication → Who are you?
Permissions → What are you allowed to do?
For example, authentication tells the API that the current user is John.
Permissions decide whether John can view, create, update, or delete a specific resource.
In this post, we will focus mainly on authentication. In the next post, we will go deeper into permissions and ownership.
Default API behaviour
At the moment, our API is public.
Anyone can access endpoints such as:
GET /api/projects/
POST /api/projects/
GET /api/tasks/
POST /api/tasks/
This means that any client can list, create, update, or delete data.
For a real application, this is usually not what we want.
Django REST Framework authentication options
Django REST Framework supports different authentication methods.
Session Authentication
Basic Authentication
Token Authentication
JWT Authentication
Each one has a different use case.
Session Authentication → Useful with Django login and browsable API
Basic Authentication → Simple, but not ideal for production APIs
Token Authentication → Simple token-based API authentication
JWT Authentication → Common for frontend and mobile applications
In this post, we will start with SessionAuthentication and BasicAuthentication, because they are simple and useful while learning.
Later, you can replace or extend this setup with token-based authentication or JWT.
Adding global authentication settings
Open your config/config/settings.py file and add a REST_FRAMEWORK configuration.
REST_FRAMEWORK = {
'DEFAULT_AUTHENTICATION_CLASSES': [
'rest_framework.authentication.SessionAuthentication',
'rest_framework.authentication.BasicAuthentication',
],
}
This tells Django REST Framework which authentication classes should be used by default.
However, this only defines how authentication is checked. It does not automatically block anonymous users yet.
Adding global permissions
To require users to be authenticated before accessing the API, we can add a default permission class.
REST_FRAMEWORK = {
'DEFAULT_AUTHENTICATION_CLASSES': [
'rest_framework.authentication.SessionAuthentication',
'rest_framework.authentication.BasicAuthentication',
],
'DEFAULT_PERMISSION_CLASSES': [
'rest_framework.permissions.IsAuthenticated',
],
}
The IsAuthenticated permission means that only authenticated users can access the API.
Authenticated user → Allowed
Anonymous user → Blocked
After adding this setting, unauthenticated requests to the API will no longer be allowed.
Testing protected endpoints
Run the development server:
python manage.py runserver
Now open one of the API endpoints in the browser:
Projects: http://localhost:8000/api/projects/
If you are not logged in, the API should return an authentication error.
{
"detail": "Authentication credentials were not provided."
}
This means the API is now protected.
Logging in through the browsable API
Django REST Framework includes login and logout views that work with the browsable API.
To enable them, open config/config/urls.py and add the authentication URLs.
from django.contrib import admin
from django.urls import path, include
urlpatterns = [
path('admin/', admin.site.urls),
path('api/', include('projects.urls')),
path('api-auth/', include('rest_framework.urls')),
]
Now, when using the browsable API in the browser, you should see login and logout options.
http://localhost:8000/api-auth/login/
http://localhost:8000/api-auth/logout/
You can log in using the superuser account created earlier.
Session Authentication
SessionAuthentication uses Django’s normal session system.
This is similar to how authentication works in the Django Admin Panel.
User logs in
Django creates a session
Browser stores the session cookie
Future requests use that session cookie
This is useful when testing the API in the browser, especially with the Django REST Framework browsable API.
However, for external clients such as mobile apps or separate frontend applications, token-based authentication is often more practical.
Basic Authentication
BasicAuthentication sends the username and password with the request.
Username + Password → Sent with the request
This can be useful for simple testing, but it should only be used over HTTPS.
In many production APIs, token-based authentication or JWT is preferred instead of sending username and password repeatedly.
Testing with curl
You can test Basic Authentication from the command line using curl.
curl -u your_username:your_password http://localhost:8000/api/projects/
If the credentials are correct, the API should return the projects response.
If the credentials are missing or incorrect, the request will be rejected.
Per-view authentication and permissions
Instead of applying authentication globally, we can also define permissions directly inside a ViewSet.
For example, open projects/views.py and update the ProjectViewSet.
from rest_framework import viewsets
from rest_framework.permissions import IsAuthenticated
from .models import Project, Task
from .serializers import ProjectSerializer, TaskSerializer
class ProjectViewSet(viewsets.ModelViewSet):
queryset = Project.objects.all()
serializer_class = ProjectSerializer
permission_classes = [IsAuthenticated]
class TaskViewSet(viewsets.ModelViewSet):
queryset = Task.objects.all()
serializer_class = TaskSerializer
permission_classes = [IsAuthenticated]
This protects only these ViewSets.
If you already configured DEFAULT_PERMISSION_CLASSES in settings.py, this is not strictly necessary, but it is useful to understand how permissions can be applied at view level.
Making one endpoint public
Sometimes we may want most of the API to be protected, but keep one endpoint public.
For example, we could allow anyone to read projects but only authenticated users to create or modify them.
For a completely public ViewSet, we could use AllowAny.
from rest_framework.permissions import AllowAny
class ProjectViewSet(viewsets.ModelViewSet):
queryset = Project.objects.all()
serializer_class = ProjectSerializer
permission_classes = [AllowAny]
This overrides the global permission setting for this ViewSet.
AllowAny → Authenticated and anonymous users are allowed
In real projects, be careful with public write access, especially for endpoints that create, update, or delete data.
Token Authentication overview
Another common option is token authentication.
With token authentication, each user or client receives a token and sends it with each request.
Client logs in or receives token
Client stores token
Client sends token with each request
Server validates token
A request using token authentication usually includes an HTTP header like this:
Authorization: Token your_token_here
Token authentication is useful for APIs consumed by external clients, but in this series we will keep the initial authentication setup simple.
JWT Authentication overview
JWT stands for JSON Web Token.
JWT authentication is very common when building APIs for frontend frameworks such as React, Vue, or Angular.
User sends login credentials
Server returns access token and refresh token
Client sends access token in future requests
Server validates the token
A JWT request usually uses an HTTP header like this:
Authorization: Bearer your_access_token_here
JWT is powerful, but it also introduces extra concepts such as access tokens, refresh tokens, expiration time, and token refresh flows.
For now, it is enough to understand that JWT is another way to authenticate API clients.
Recommended learning setup
For this series, a good starting setup is:
REST_FRAMEWORK = {
'DEFAULT_AUTHENTICATION_CLASSES': [
'rest_framework.authentication.SessionAuthentication',
'rest_framework.authentication.BasicAuthentication',
],
'DEFAULT_PERMISSION_CLASSES': [
'rest_framework.permissions.IsAuthenticated',
],
}
This keeps the API protected while still being easy to test in the browser and from the command line.
Later, when connecting this API to a frontend application, JWT authentication can be added as a more realistic production option.
What we have learned
In this post, we added authentication to our Django REST API.
Authentication identifies who is making a request
Permissions decide what the user can do
SessionAuthentication works well with the browsable API
BasicAuthentication can be useful for testing
IsAuthenticated protects API endpoints
Authentication can be configured globally or per view
Token and JWT authentication are common alternatives for real API clients
Our API is now protected and no longer fully public.
What comes next?
In the next post, we will go deeper into permissions and ownership.
We will make sure users can only access and manage their own projects and tasks.
Django REST API: Permissions and Ownership