Introduction
Authentication is one of the most important aspects of any web application, especially APIs. When building APIs using Django REST Framework (DRF), securing your endpoints to ensure that only authorized users can access or manipulate data is a critical step. DRF provides several built-in authentication mechanisms that can be easily integrated into your project. Among these, Token-Based Authentication is one of the most common and effective methods, particularly for APIs that serve mobile applications or single-page web apps.
This post will give you a complete understanding of token-based authentication in Django REST Framework. We will explore how it works, how to set it up, how to generate and use tokens, and how to secure your API endpoints with tokens. We will also discuss best practices and some common mistakes developers make while implementing authentication in DRF.
Understanding Authentication in Django REST Framework
What Is Authentication?
Authentication is the process of verifying the identity of a user or system trying to access your application. It ensures that only users with valid credentials can interact with certain resources or perform specific actions.
In Django REST Framework, authentication works alongside permissions and throttling to control access to APIs. Authentication identifies who the user is, while permissions determine what they can do.
Why Token-Based Authentication?
Traditional web applications rely on session-based authentication, where the user logs in once, and the server stores a session ID in the database. However, with APIs—especially those that serve mobile clients or external services—storing session data server-side can be inconvenient.
Token-based authentication solves this by issuing a token to the user after they authenticate. This token is then included in every subsequent request to verify the user’s identity.
Benefits of token-based authentication:
- Stateless: No session data is stored on the server.
- Scalable: Works well with distributed systems.
- Simple to use across different platforms (mobile, web, etc.).
- Secure: Can be combined with HTTPS for safe communication.
Setting Up Token Authentication in Django REST Framework
Let’s now go step-by-step to enable Token Authentication in a DRF project.
Step 1: Install Django REST Framework
If you haven’t already installed DRF, you can add it using pip:
pip install djangorestframework
Add 'rest_framework' to your INSTALLED_APPS in settings.py.
Step 2: Add Token Authentication App
Token authentication is provided by the rest_framework.authtoken app, which comes bundled with DRF. Add it to your installed apps as well:
INSTALLED_APPS = [
'django.contrib.admin',
'django.contrib.auth',
'django.contrib.contenttypes',
'django.contrib.sessions',
'django.contrib.messages',
'django.contrib.staticfiles',
'rest_framework',
'rest_framework.authtoken',
'myapp', # your app
]
Step 3: Run Migrations to Create Token Model
Django REST Framework includes a built-in model called Token that stores user tokens in the database. To create this table, run:
python manage.py migrate
After running migrations, you’ll now have a new database table: authtoken_token, which stores tokens associated with users.
Step 4: Create Tokens for Users
You can generate a token for a user manually using the Django shell:
python manage.py shell
Then, inside the shell:
from rest_framework.authtoken.models import Token
from django.contrib.auth.models import User
user = User.objects.get(username='admin')
token = Token.objects.create(user=user)
print(token.key)
This prints a unique key, for example:
1a2b3c4d5e6f7g8h9i0j
This token is now linked to the user admin and can be used to authenticate API requests.
Step 5: Configure Authentication in Settings
Now that the token model is ready, you need to tell Django REST Framework to use TokenAuthentication as the default authentication method. In settings.py, add:
REST_FRAMEWORK = {
'DEFAULT_AUTHENTICATION_CLASSES': [
'rest_framework.authentication.TokenAuthentication',
]
}
This setting ensures that all DRF views and viewsets automatically check for tokens in incoming requests.
Step 6: Sending Tokens with API Requests
Once a token is generated for a user, clients (such as mobile apps, web apps, or Postman) need to include it in the header of every API request.
Example of a request header:
Authorization: Token your_token_here
For example, if your token is 1a2b3c4d5e6f7g8h9i0j, the header will look like this:
Authorization: Token 1a2b3c4d5e6f7g8h9i0j
This tells the server that the request is coming from an authenticated user.
Step 7: Example of Token Authentication in an API View
Here’s a complete example showing how to protect an API endpoint using token authentication.
from rest_framework.views import APIView
from rest_framework.response import Response
from rest_framework.permissions import IsAuthenticated
class SecureDataView(APIView):
permission_classes = [IsAuthenticated]
def get(self, request):
data = {"message": f"Hello, {request.user.username}! This is a protected endpoint."}
return Response(data)
In this example:
- Only authenticated users (with valid tokens) can access this view.
- If a user tries to access this endpoint without providing a valid token, they’ll receive a 401 Unauthorized error.
Step 8: Automatically Generating Tokens When Users Register
In most applications, you’ll want a token to be automatically created for every new user. You can achieve this using Django signals.
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)
This code ensures that whenever a new user is created, a token is automatically generated and associated with that user.
Step 9: Using Token Authentication with the Browsable API
If you are using DRF’s browsable API interface, you can also authenticate by logging in through the browser. By default, the browsable API includes a login option that uses Django’s session authentication.
If you want to test Token Authentication directly from the browsable API, you can add an endpoint for obtaining tokens.
Step 10: Creating a Token Login Endpoint
DRF provides a built-in view for obtaining tokens. You can include it in your URLs like this:
from django.urls import path
from rest_framework.authtoken.views import obtain_auth_token
urlpatterns = [
path('api/token/', obtain_auth_token, name='api_token_auth'),
]
Now you can send a POST request to /api/token/ with username and password to get a token.
Example request (using Postman or curl):
POST /api/token/
Content-Type: application/json
{
"username": "admin",
"password": "adminpassword"
}
Response:
{
"token": "1a2b3c4d5e6f7g8h9i0j"
}
This endpoint allows users to authenticate using their credentials and receive their unique token in response.
Step 11: Testing Token Authentication
Let’s test the whole setup using curl or Postman.
Step 11.1: Get Token
POST http://localhost:8000/api/token/
with JSON body:
{
"username": "admin",
"password": "adminpassword"
}
You’ll receive:
{
"token": "1a2b3c4d5e6f7g8h9i0j"
}
Step 11.2: Access Protected Endpoint
GET http://localhost:8000/api/secure-data/
Add header:
Authorization: Token 1a2b3c4d5e6f7g8h9i0j
Response:
{
"message": "Hello, admin! This is a protected endpoint."
}
Without token, you’ll get:
{
"detail": "Authentication credentials were not provided."
}
Step 12: Handling Token Expiration (Optional)
By default, DRF tokens do not expire. However, in production, you might want tokens to expire after a certain period. You can either:
- Use third-party packages such as djangorestframework-simplejwt, or
- Create a custom token model with an expiry field.
Example using Simple JWT:
pip install djangorestframework-simplejwt
Then in your settings:
REST_FRAMEWORK = {
'DEFAULT_AUTHENTICATION_CLASSES': (
'rest_framework_simplejwt.authentication.JWTAuthentication',
),
}
Simple JWT provides more advanced features such as token refresh, rotation, and expiration.
Step 13: Logging Out and Deleting Tokens
Unlike session-based authentication, token-based authentication doesn’t automatically handle logout. However, you can manually delete a token to invalidate it.
Example:
from rest_framework.views import APIView
from rest_framework.response import Response
from rest_framework.permissions import IsAuthenticated
class LogoutView(APIView):
permission_classes = [IsAuthenticated]
def post(self, request):
request.user.auth_token.delete()
return Response({"message": "Token deleted successfully. You are logged out."})
When a user logs out, their token is deleted from the database, effectively logging them out.
Step 14: Combining Token Authentication with Permissions
Authentication identifies who the user is, but you also need to define permissions to control what they can access.
For example:
from rest_framework.permissions import IsAuthenticated, IsAdminUser
class AdminOnlyView(APIView):
permission_classes = [IsAuthenticated, IsAdminUser]
def get(self, request):
return Response({"message": "Welcome, Admin!"})
This ensures that only authenticated users who are also admin users can access this endpoint.
Step 15: Common Issues and Troubleshooting
1. Token Not Created Automatically
Ensure your signal is properly registered, and the rest_framework.authtoken app is installed.
2. Authentication Credentials Not Provided
Check that your request header includes:
Authorization: Token your_token_here
3. Invalid Token
If a user logs out or their token is deleted, you’ll need to reissue a new one.
4. Using Both Session and Token Authentication
You can support multiple authentication types simultaneously:
REST_FRAMEWORK = {
'DEFAULT_AUTHENTICATION_CLASSES': [
'rest_framework.authentication.SessionAuthentication',
'rest_framework.authentication.TokenAuthentication',
]
}
Step 16: Token Authentication vs JWT Authentication
| Feature | Token Authentication | JWT Authentication |
|---|---|---|
| Storage | Server-side (database) | Client-side (self-contained) |
| Expiry | No expiry by default | Built-in expiry support |
| Revocation | Delete token from DB | Requires token blacklist |
| Simplicity | Simple to implement | Slightly complex |
| Best for | Small to medium apps | Large-scale distributed apps |
For many small projects or internal APIs, Django’s built-in token authentication is sufficient. For more complex systems, JWT might be a better choice.
Step 17: Best Practices for Token Authentication
- Always use HTTPS
Never transmit tokens over unsecured HTTP connections. - Regenerate tokens periodically
Avoid long-lived tokens for better security. - Use custom authentication classes for specific needs
You can subclassTokenAuthenticationto add features like token expiration or IP binding. - Log token usage
Track when and where tokens are used for auditing purposes. - Limit access by role or permission
Combine token authentication with fine-grained permission control.
Step 18: Custom Token Authentication (Advanced Example)
You can customize token authentication by extending DRF’s TokenAuthentication class.
Example:
from rest_framework.authentication import TokenAuthentication
from rest_framework.exceptions import AuthenticationFailed
class ExpiringTokenAuthentication(TokenAuthentication):
def authenticate_credentials(self, key):
user, token = super().authenticate_credentials(key)
if token.created < timezone.now() - timedelta(hours=24):
raise AuthenticationFailed('Token has expired')
return (user, token)
Then set it in settings.py:
REST_FRAMEWORK = {
'DEFAULT_AUTHENTICATION_CLASSES': [
'myapp.authentication.ExpiringTokenAuthentication',
]
}
This implementation adds a 24-hour token expiry window.
Step 19: Example Project Directory Overview
Here’s what your project structure might look like:
myproject/
│
├── myapp/
│ ├── models.py
│ ├── views.py
│ ├── serializers.py
│ ├── urls.py
│
├── myproject/
│ ├── settings.py
│ ├── urls.py
│
└── manage.py
You can organize your token endpoints inside myapp/urls.py for clarity.
Leave a Reply