from __future__ import annotations from django.utils.translation import gettext_lazy as _ from rest_framework import authentication, exceptions from apps.accounts.models import ApiKey class ApiKeyAuthentication(authentication.BaseAuthentication): """Authenticate via X-API-Key header (hashed lookup).""" keyword = "X-API-Key" def authenticate(self, request): raw_key = request.headers.get(self.keyword) or request.META.get("HTTP_X_API_KEY") if not raw_key: return None if len(raw_key) < 8: raise exceptions.AuthenticationFailed(_("Invalid API key")) prefix = raw_key[:8] candidates = ApiKey.objects.select_related("user").filter( prefix=prefix, is_active=True, user__is_active=True ) for api_key in candidates: if api_key.verify(raw_key): api_key.touch() return (api_key.user, api_key) raise exceptions.AuthenticationFailed(_("Invalid API key")) def authenticate_header(self, request): return self.keyword