Files
AdventureLog/backend/server/users/authentication.py
Sean Morley 1dcf99be7d feat: add API key management to settings page
- Implemented API key creation, deletion, and display functionality.
- Updated the settings page to fetch and show existing API keys.
- Added UI elements for creating new API keys and copying them to clipboard.
- Enhanced request handling to ensure proper trailing slashes for API endpoints.
2026-03-16 15:14:32 -04:00

53 lines
1.6 KiB
Python

"""
Custom DRF authentication backend for AdventureLog API keys.
Clients may supply their key via either of these headers:
Authorization: Api-Key al_xxxxxxxxxxxxxxxx...
X-API-Key: al_xxxxxxxxxxxxxxxx...
Session-based CSRF enforcement is performed by DRF's built-in
``SessionAuthentication`` class only. Requests authenticated via this
class are never subject to CSRF checks, which is the correct behaviour
for token-based API access.
"""
from rest_framework.authentication import BaseAuthentication
from rest_framework.exceptions import AuthenticationFailed
class APIKeyAuthentication(BaseAuthentication):
"""Authenticate a request using an AdventureLog API key."""
def authenticate(self, request):
raw_key = self._extract_key(request)
if raw_key is None:
# Signal to DRF that this scheme was not attempted so other
# authenticators can still run.
return None
from .models import APIKey
api_key = APIKey.authenticate(raw_key)
if api_key is None:
raise AuthenticationFailed("Invalid or expired API key.")
return (api_key.user, api_key)
def authenticate_header(self, request):
return "Api-Key"
@staticmethod
def _extract_key(request) -> str | None:
# Prefer X-API-Key header for simplicity.
key = request.META.get("HTTP_X_API_KEY")
if key:
return key.strip()
# Also accept "Authorization: Api-Key <token>"
auth_header = request.META.get("HTTP_AUTHORIZATION", "")
if auth_header.lower().startswith("api-key "):
return auth_header[8:].strip()
return None