Skip to main content

Machine-to-machine API key authentication for Django REST Framework

Project description

django_machine_auth

PyPI

API key authentication for Django REST Framework with module-scoped permissions (similar to how platforms like GitHub, Stripe, or OpenAI expose scoped API keys).

Current version: 0.3.0 — permission catalog, API key management, and request log REST APIs.

Documentation map

Guide Audience
setup.md Full step-by-step setup (recommended for first integration)
This README Quick reference and viewset overview

Topics in setup.md

  1. Installation and settings
  2. Part I — Define permissions in code
  3. Part II — Protect your APIs (MachineAuthViewSet)
  4. Part III — Permission catalog API (MachinePermissionViewSet)
  5. Part IV — API key management
  6. Part V — Call protected APIs with an API key
  7. Part VII — Request logs API
  8. Logging, commands, troubleshooting

Viewsets at a glance

The package provides four viewsets for four different jobs. Do not mix them up.

Viewset When to use Inherit in your project? Auth on requests
MachineAuthViewSet Protect your business APIs (integrations call these) Yes Authorization: machine_auth <key>
MachinePermissionViewSet List permissions for assignment UI (dropdowns) Optional (subclass to filter) JWT / session (your DRF auth)
MachineAPIKeyManagementViewSet Create/list/update/revoke keys Usually no (use package URLs) JWT / session (your DRF auth)
MachineAPIKeyRequestLogViewSet List/inspect machine-auth request logs Usually no (use package URLs) JWT / session (your DRF auth)

Import from:

from django_machine_auth.views import (
    MachineAuthViewSet,
    MachinePermissionViewSet,
    MachineAPIKeyManagementViewSet,
    MachineAPIKeyRequestLogViewSet,
)

Quick start

1. Install and configure

pip install django-machine-auth
INSTALLED_APPS = ["django_machine_auth", ...]

MACHINE_AUTH = {
    "KEY_PREFIX": "mac_",
    "ENABLE_REQUEST_LOGGING": False,
    "LOGGING_MODE": "redacted",
    "CACHE_TIMEOUT": 3600,
}

REST_FRAMEWORK = {
    "DEFAULT_THROTTLE_RATES": {
        "machine_api_key": "1000/hour",
    },
}

2. Wire management URLs (one line)

path("machine-auth/", include("django_machine_auth.urls")),

3. Define permissions in code

your_app/api_key_perm.py:

from django_machine_auth.decorators import api_key_module


@api_key_module("complaint", label="Complaint")
class ComplaintModule:
    crud = ["view", "create", "update", "delete"]
    actions = {"export": ["get"]}

Then:

python manage.py machine_auth_sync

4. Protect your API — inherit MachineAuthViewSet

from rest_framework import mixins
from rest_framework.response import Response
from django_machine_auth.views import MachineAuthViewSet


class ComplaintMachineViewSet(MachineAuthViewSet, mixins.ListModelMixin):
    module = "complaint"  # required — must match api_key_perm.py

    def get_queryset(self):
        return Complaint.objects.filter(...)

    def list(self, request):
        return Response(ComplaintSerializer(self.get_queryset(), many=True).data)

Register on your router (e.g. /v1/complaint/machine/).

5. Create keys and call your API

Management (JWT/session):

POST /machine-auth/machine-api-keys/

Integration call:

GET /v1/complaint/machine/
Authorization: machine_auth mac_xxxxx

MachineAuthViewSet (protect your APIs)

Purpose: Endpoints that external systems call using an API key.

What it provides automatically:

  • MachineAPIKeyAuthentication
  • MachineAuthPermission (checks key’s permission list vs action + HTTP method)
  • MachineAPIKeyRateThrottle

You must:

  1. Set module = "<name>" matching @api_key_module("<name>").
  2. Add DRF mixins (ListModelMixin, etc.) and implement actions.
  3. Declare custom @action names in api_key_perm.py under actions.
  4. If mixing with another base viewset (e.g. JWT), put MachineAuthViewSet first in inheritance, or set authentication_classes / permission_classes explicitly on the combined class.

Permission mapping:

DRF action Required permission
list, retrieve module.view
create module.create
update, partial_update module.update
destroy module.delete
custom @action module.<action>.<method_lower>

After auth: request.machine_api_key is set; use request.machine_api_key.permissions if needed.

Details: setup.md — Part II.


MachinePermissionViewSet (permission catalog)

Purpose: Return assignable permissions from the database (for UI when creating/updating keys).

Default route (no subclass needed):

  • GET /machine-auth/permissions/
  • GET /machine-auth/permissions/?module=complaint
  • GET /machine-auth/permissions/?search=export

Restrict what users can assign — subclass and override get_queryset():

from django_machine_auth.views import MachinePermissionViewSet


class ComplaintPermissionViewSet(MachinePermissionViewSet):
    def get_queryset(self):
        return super().get_queryset().filter(module="complaint")

Register the subclass on your router only if you need a custom path; otherwise use built-in filters.

Details: setup.md — Part III.


API key management

Purpose: Create, list, inspect, update, and revoke API keys (admin portal / internal API).

Use package URLs (recommended):

Method Path
GET /machine-auth/permissions/
GET /machine-auth/machine-api-keys/
POST /machine-auth/machine-api-keys/
GET /machine-auth/machine-api-keys/{id}/
PATCH /machine-auth/machine-api-keys/{id}/
POST /machine-auth/machine-api-keys/{id}/deactivate/

Access:

  • Superuser: all keys; create for any user; list filter ?user=<id>.
  • Authenticated user: own keys only; create only for self.

raw_api_key is returned once on create. List/retrieve never expose hashed_key.

Details: setup.md — Part IV.


Request logs API

Purpose: Browse audit logs for machine-authenticated API calls (SuperAdmin portal or user self-service).

Prerequisites: ENABLE_REQUEST_LOGGING = True and MachineAuthLoggingMiddleware installed.

Method Path
GET /machine-auth/request-logs/
GET /machine-auth/request-logs/{id}/

Access:

  • Superuser: all logs; ?user=<id>, ?api_key=<id>.
  • Authenticated user: logs for API keys they own; ?api_key=<id> (403 if not their key).

List returns metadata only (method, url, status, duration, etc.). Detail includes headers, request_body, response_body when stored.

Details: setup.md — Part VII.


Three “permission” concepts (do not confuse)

Concept Where it lives Used for
Module definition api_key_perm.py in your app Source of truth in code
Permission registry MachinePermission table Validation + catalog API
Key permissions MachineAPIKey.permissions JSON Runtime checks on protected APIs

Flow: codemachine_auth_syncDB → assign on key → MachineAuthViewSet enforces on each request.


Logging

MIDDLEWARE = [
    "django_machine_auth.middleware.logging_middleware.MachineAuthLoggingMiddleware",
]
MACHINE_AUTH = {"ENABLE_REQUEST_LOGGING": True, "LOGGING_MODE": "redacted"}

Only requests with successful machine auth context are logged.


Management commands

python manage.py machine_auth_sync          # DB ← code permissions
python manage.py machine_auth_permissions   # print permission docs

Troubleshooting

  • 403 on protected API: key missing exact permission string (e.g. complaint.export.get).
  • 401: invalid/expired/inactive key or wrong KEY_PREFIX.
  • Module not registered: view.module must match api_key_perm.py; run sync.
  • Throttle error: set machine_api_key in DEFAULT_THROTTLE_RATES.
  • Logging empty: middleware enabled + valid machine auth on request.
  • Log API 403 on ?api_key=: key belongs to another user.

More

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

django_machine_auth-0.3.0.tar.gz (34.7 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

django_machine_auth-0.3.0-py3-none-any.whl (30.5 kB view details)

Uploaded Python 3

File details

Details for the file django_machine_auth-0.3.0.tar.gz.

File metadata

  • Download URL: django_machine_auth-0.3.0.tar.gz
  • Upload date:
  • Size: 34.7 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.13.7

File hashes

Hashes for django_machine_auth-0.3.0.tar.gz
Algorithm Hash digest
SHA256 61c5e589439f23820e81d59af28e68ad3898ecaaec3127ece3d1fb6bf2a8e2d2
MD5 cb7a5116379eb2e7c65f029d6f950058
BLAKE2b-256 8cc6ecf47a8e862b61745b4e74eb50794b70231e2affa37709ee6fdd0cbc14dc

See more details on using hashes here.

File details

Details for the file django_machine_auth-0.3.0-py3-none-any.whl.

File metadata

File hashes

Hashes for django_machine_auth-0.3.0-py3-none-any.whl
Algorithm Hash digest
SHA256 47418041e7d22dff9fb4ef8d1727218056262d2ecb8cd281da829e2f742c7f00
MD5 aa3b7e71312b8044b171d851b37a218e
BLAKE2b-256 85d22d8c98deea3bbbd7d192d401c668f1a32880ae7dd135ade8bd4b5f7b8e37

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page