Skip to content

Django REST Framework integration

Keysmith integrates with DRF's authentication and permission system. Install the optional extra and configure two classes.


Setup

pip install "django-keysmith[drf]"
REST_FRAMEWORK = {
    "DEFAULT_AUTHENTICATION_CLASSES": [
        "keysmith.drf.auth.KeysmithAuthentication",
    ],
    "DEFAULT_PERMISSION_CLASSES": [
        "keysmith.drf.permissions.RequireKeysmithToken",
    ],
}

Per-view overrides work as usual - global defaults just reduce boilerplate.


How it works

flowchart TD
    A[DRF request] --> B[KeysmithAuthentication]
    B --> C{Token present?}
    C -->|No| D[Return None - other auth may run]
    C -->|Yes| E[authenticate_token]
    E -->|Error| F[AuthenticationFailed 401]
    E -->|OK| G[DRF_THROTTLE_HOOK]
    G --> H["Return (user, token)"]
    H --> I[Permission classes run]
    I --> J[View logic]

After authentication:

  • request.authToken instance
  • request.usertoken.user or DRF's unauthenticated user

Basic endpoint

from rest_framework.response import Response
from rest_framework.views import APIView


class StatusView(APIView):
    def get(self, request):
        return Response({
            "prefix": request.auth.prefix,
            "user_id": getattr(request.user, "pk", None),
        })

Requiring authentication explicitly

from keysmith.drf.permissions import RequireKeysmithToken


class StatusView(APIView):
    permission_classes = [RequireKeysmithToken]

RequireKeysmithToken raises NotAuthenticated when request.auth is missing.


Scope-protected endpoints

from keysmith.drf.permissions import RequireKeysmithToken, ScopedPermission


class WriteView(APIView):
    permission_classes = [RequireKeysmithToken, ScopedPermission("write")]

    def post(self, request):
        return Response({"created": True})

See Scopes for HasKeysmithScopes and view-level required_scopes.


Throttling

from rest_framework.exceptions import Throttled

KEYSMITH = {
    "DRF_THROTTLE_HOOK": "myapp.hooks.throttle",
}


def throttle(request, token=None):
    if should_throttle(token):
        raise Throttled(detail="Too many requests")

Runs after successful authentication, before the view.


Client usage

curl -H "X-KEYSMITH-TOKEN: <raw-token>" http://localhost:8000/api/status/

Testing

client.credentials(HTTP_X_KEYSMITH_TOKEN=raw_token)
response = client.get("/api/status/")
assert response.status_code == 200

Middleware coexistence

Keysmith middleware and DRF auth can run together. DRF sets _keysmith_skip_middleware_audit on the underlying Django request to prevent duplicate audit events.


See also: Authentication · Permissions reference