Machine-to-machine API key authentication for Django REST Framework
Project description
django_machine_auth
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
- Installation and settings
- Part I — Define permissions in code
- Part II — Protect your APIs (
MachineAuthViewSet) - Part III — Permission catalog API (
MachinePermissionViewSet) - Part IV — API key management
- Part V — Call protected APIs with an API key
- Part VII — Request logs API
- 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:
MachineAPIKeyAuthenticationMachineAuthPermission(checks key’s permission list vs action + HTTP method)MachineAPIKeyRateThrottle
You must:
- Set
module = "<name>"matching@api_key_module("<name>"). - Add DRF mixins (
ListModelMixin, etc.) and implement actions. - Declare custom
@actionnames inapi_key_perm.pyunderactions. - If mixing with another base viewset (e.g. JWT), put
MachineAuthViewSetfirst in inheritance, or setauthentication_classes/permission_classesexplicitly 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=complaintGET /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: code → machine_auth_sync → DB → 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.modulemust matchapi_key_perm.py; run sync. - Throttle error: set
machine_api_keyinDEFAULT_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
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
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
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
61c5e589439f23820e81d59af28e68ad3898ecaaec3127ece3d1fb6bf2a8e2d2
|
|
| MD5 |
cb7a5116379eb2e7c65f029d6f950058
|
|
| BLAKE2b-256 |
8cc6ecf47a8e862b61745b4e74eb50794b70231e2affa37709ee6fdd0cbc14dc
|
File details
Details for the file django_machine_auth-0.3.0-py3-none-any.whl.
File metadata
- Download URL: django_machine_auth-0.3.0-py3-none-any.whl
- Upload date:
- Size: 30.5 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.13.7
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
47418041e7d22dff9fb4ef8d1727218056262d2ecb8cd281da829e2f742c7f00
|
|
| MD5 |
aa3b7e71312b8044b171d851b37a218e
|
|
| BLAKE2b-256 |
85d22d8c98deea3bbbd7d192d401c668f1a32880ae7dd135ade8bd4b5f7b8e37
|