Token-Based Authentication in Web APIs

Last updated 1 month, 1 week ago | 104 views 75     5

Tags:- Python Django DRF

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

  1. Login: User sends credentials to the server.

  2. Token Issued: Server responds with a token.

  3. Use Token: Client sends the token in headers for every protected request.

  4. 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

  1. Always Use HTTPS
    Tokens can be intercepted if sent over plain HTTP.

  2. Token Expiration
    Default DRF tokens never expire. Use libraries like djangorestframework-simplejwt for expiring tokens.

  3. Secure Storage
    Store tokens securely on the client (e.g., in SecureStorage or encrypted storage for mobile apps).

  4. Logout
    To simulate logout, just delete the token server-side and instruct the client to remove it.

  5. 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