Token-based authentication is a stateless and secure method to authenticate users in modern web applications and APIs. It provides an efficient alternative to traditional session-based authentication, particularly suited for RESTful APIs, mobile apps, and Single Page Applications (SPAs).
This article covers:
-
What token-based authentication is
-
How it works
-
Implementation in Django Rest Framework
-
Code examples
-
Tips and pitfalls
What is Token-Based Authentication?
Token-based authentication is a method where a user logs in with credentials, and receives a token in response. This token is then used to access protected resources.
The Authentication Flow
-
Login: User sends credentials to the server.
-
Token Issued: Server responds with a token.
-
Use Token: Client sends the token in headers for every protected request.
-
Server Validates: Server verifies the token and grants access.
Why Use Tokens?
Feature | Token-Based | Session-Based |
---|---|---|
Stateless | ✅ Yes | ❌ No |
Mobile Friendly | ✅ Yes | ❌ Limited |
CSRF Protection Needed | ❌ No | ✅ Yes |
Scalable | ✅ Easier | ❌ Harder |
Server Stores Data | ❌ No | ✅ Yes |
Token Authentication in Django Rest Framework (DRF)
Step 1: Install and Configure DRF
pip install djangorestframework
Add to your settings.py
:
INSTALLED_APPS = [
...
'rest_framework',
'rest_framework.authtoken',
]
REST_FRAMEWORK = {
'DEFAULT_AUTHENTICATION_CLASSES': [
'rest_framework.authentication.TokenAuthentication',
],
'DEFAULT_PERMISSION_CLASSES': [
'rest_framework.permissions.IsAuthenticated',
],
}
Run the migration to create the token model:
python manage.py migrate
Step 2: Generate Tokens
Automatically on User Creation (optional)
Add this signal to models.py
or a signals.py
:
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)
Don't forget to connect signals in apps.py
.
Step 3: Token Login Endpoint
In your urls.py
:
from django.urls import path
from rest_framework.authtoken.views import obtain_auth_token
urlpatterns = [
path('api/token/', obtain_auth_token),
]
This view accepts POST requests with a username
and password
, and returns a token:
curl -X POST -d "username=admin&password=admin123" http://127.0.0.1:8000/api/token/
Response:
{"token": "0123456789abcdef0123456789abcdef"}
Step 4: Use the Token in API Requests
Send the token in the HTTP Authorization
header:
curl -H "Authorization: Token 0123456789abcdef0123456789abcdef" http://127.0.0.1:8000/api/protected/
Step 5: Protect a View with Token Authentication
from rest_framework.views import APIView
from rest_framework.response import Response
from rest_framework.authentication import TokenAuthentication
from rest_framework.permissions import IsAuthenticated
class ProtectedView(APIView):
authentication_classes = [TokenAuthentication]
permission_classes = [IsAuthenticated]
def get(self, request):
return Response({"message": f"Welcome {request.user.username}"})
✅ Complete Example
Project structure:
myproject/
├── manage.py
├── myapp/
│ ├── views.py
│ ├── urls.py
├── myproject/
│ ├── settings.py
│ ├── urls.py
views.py
from rest_framework.views import APIView
from rest_framework.response import Response
from rest_framework.authentication import TokenAuthentication
from rest_framework.permissions import IsAuthenticated
class HelloUser(APIView):
authentication_classes = [TokenAuthentication]
permission_classes = [IsAuthenticated]
def get(self, request):
return Response({'message': f'Hello, {request.user.username}!'})
urls.py
(in app)
from django.urls import path
from .views import HelloUser
from rest_framework.authtoken.views import obtain_auth_token
urlpatterns = [
path('hello/', HelloUser.as_view()),
path('token/', obtain_auth_token),
]
Main urls.py
from django.contrib import admin
from django.urls import path, include
urlpatterns = [
path('admin/', admin.site.urls),
path('api/', include('myapp.urls')),
]
Tips and Best Practices
-
Always Use HTTPS
Tokens can be intercepted if sent over plain HTTP. -
Token Expiration
Default DRF tokens never expire. Use libraries likedjangorestframework-simplejwt
for expiring tokens. -
Secure Storage
Store tokens securely on the client (e.g., inSecureStorage
or encrypted storage for mobile apps). -
Logout
To simulate logout, just delete the token server-side and instruct the client to remove it. -
Token Rotation
Regenerate tokens on a regular basis for better security.
⚠️ Common Pitfalls
Pitfall | Explanation |
---|---|
❌ Sending token in wrong format | Header must be Authorization: Token <token> , not Bearer . |
❌ Not using HTTPS | Tokens are exposed to sniffing attacks. |
❌ Forgetting IsAuthenticated |
Without this permission, your views may be accessible without a token. |
❌ Tokens never expire | Could be a security issue unless managed. |
❌ Storing tokens in localStorage (for web apps) | Vulnerable to XSS. Use httpOnly cookies if possible. |
Conclusion
Token-based authentication is ideal for building secure and scalable APIs. DRF makes it easy to implement, and you can enhance it further with third-party libraries for refresh tokens, expiration, and more secure features.
For more advanced use cases, consider exploring:
-
djangorestframework-simplejwt
(JWT support) -
OAuth2 via
django-oauth-toolkit
-
Multi-device token management