python / intermediate
Snippet
Django REST Framework Authentication Classes
Custom authentication classes in Django REST Framework allow you to implement any authentication mechanism by extending BaseAuthentication. This example implements HMAC-based authentication with timestamp validation to prevent replay attacks. The authenticate() method returns either None (allowing other authenticators) or a tuple of (user, auth) that DRF uses to set request.user.
snippet.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
from rest_framework.authentication import BaseAuthenticationfrom rest_framework.exceptions import AuthenticationFailedfrom django.contrib.auth.models import Userimport hmacclass HMACAuthentication(BaseAuthentication):def authenticate(self, request):signature = request.META.get('HTTP_X_SIGNATURE')timestamp = request.META.get('HTTP_X_TIMESTAMP')if not signature or not timestamp:return Noneif not self.is_valid_timestamp(timestamp):raise AuthenticationFailed('Request expired')secret = self.get_user_secret(request)expected = hmac.new(secret.encode(),timestamp.encode(),hashlib.sha256).hexdigest()if not hmac.compare_digest(signature, expected):raise AuthenticationFailed('Invalid signature')user = self.get_user_from_request(request)return (user, None)def is_valid_timestamp(self, timestamp):import timereturn abs(time.time() - float(timestamp)) < 300def get_user_secret(self, request):api_key = request.META.get('HTTP_X_API_KEY', '')return f'secret_{api_key}'def get_user_from_request(self, request):return User.objects.get(username='api_user')
django
Breakdown
1
class HMACAuthentication(BaseAuthentication):
Extend BaseAuthentication to create a custom authentication method
2
if not signature or not timestamp: return None
Return None when credentials missing, letting DRF try next authenticator
3
raise AuthenticationFailed('Request expired')
Raise exception when validation fails to reject the request immediately
4
hmac.compare_digest(signature, expected)
Use constant-time comparison to prevent timing attacks
5
return (user, None)
Return tuple: user object and authentication info (None here)