Django Integration¶
keyshield supports Django 4.1+ via the
keyshield.django package.
The integration provides:
| Component | Purpose |
|---|---|
DjangoApiKeyRepository |
Django ORM repository (replaces SQLAlchemy) |
ApiKeyListCreateView / ApiKeyDetailView / … |
Async class-based views for CRUD management |
create_api_keys_urlpatterns |
URL pattern factory |
require_api_key |
Async view decorator for route protection |
Installation¶
uv add keyshield[django]
Setup¶
Add the app to INSTALLED_APPS in your Django settings:
# settings.py
INSTALLED_APPS = [
...
"keyshield.django",
]
Then run migrations to create the api_keys table:
python manage.py makemigrations keyshield_django
python manage.py migrate
Quick start¶
# myapp/api_keys.py
from keyshield.django import DjangoApiKeyRepository
from keyshield.services.base import ApiKeyService
from keyshield.hasher.argon2 import Argon2ApiKeyHasher
async def get_service() -> ApiKeyService:
return ApiKeyService(
repo=DjangoApiKeyRepository(),
hasher=Argon2ApiKeyHasher(pepper="your-secret-pepper"),
)
Register the management endpoints in your URL configuration:
# myapp/urls.py
from django.urls import path, include
from keyshield.django.urls import create_api_keys_urlpatterns
from myapp.api_keys import get_service
urlpatterns = [
path("api-keys/", include(create_api_keys_urlpatterns(svc_factory=get_service))),
]
Protecting views¶
Use the require_api_key decorator on any async view:
from django.http import JsonResponse
from keyshield.django.decorators import require_api_key
from myapp.api_keys import get_service
@require_api_key(svc_factory=get_service)
async def my_protected_view(request):
key = request.api_key # verified ApiKey entity
return JsonResponse({"key_id": key.key_id})
Scope-restricted views¶
@require_api_key(svc_factory=get_service, required_scopes=["admin"])
async def admin_view(request):
return JsonResponse({"admin": True})
Management endpoints¶
create_api_keys_urlpatterns mounts these routes:
| Method | Path | Description |
|---|---|---|
POST |
/api-keys/ |
Create a new key (returns plaintext once) |
GET |
/api-keys/ |
List keys (paginated with ?offset= / ?limit=) |
GET |
/api-keys/<id>/ |
Get a key by ID |
PATCH |
/api-keys/<id>/ |
Partially update a key |
DELETE |
/api-keys/<id>/ |
Delete a key |
POST |
/api-keys/<id>/activate/ |
Activate a key |
POST |
/api-keys/<id>/deactivate/ |
Deactivate a key |
POST |
/api-keys/search/ |
Search with filters |
POST |
/api-keys/count/ |
Count keys matching a filter |
POST |
/api-keys/verify/ |
Verify a key |
Custom service factory¶
Django's as_view(svc_factory=...) pattern is used for dependency injection.
You can wire up any service factory, including one backed by caching:
from keyshield.services.cached import CachedApiKeyService
async def get_service() -> CachedApiKeyService:
return CachedApiKeyService(
repo=DjangoApiKeyRepository(),
hasher=Argon2ApiKeyHasher(pepper="pepper"),
cache_ttl=300,
)
Dev mode (.env keys)¶
import os
os.environ["API_KEY_DEV"] = "ak_v1-mydevkeyid-mysecret64chars"
async def get_service() -> ApiKeyService:
svc = ApiKeyService(repo=DjangoApiKeyRepository(), hasher=Argon2ApiKeyHasher())
await svc.load_dotenv(envvar_prefix="API_KEY_")
return svc
Notes¶
- All views are
asyncand require Django 4.1+ (native async ORM support). - The repository uses Django's default database connection — no session management needed.
- Scope filters (
scopes_contain_all,scopes_contain_any) are applied in Python after fetching, ensuring compatibility across SQLite, PostgreSQL, and MySQL.