Authentication, object permissions and audit records¶
This project combines django-filter, django-guardian, djangorestframework-guardian, rules, django-simple-history, django-auditlog, django-oauth-toolkit, Djoser, dj-rest-auth, django-allauth, django-cors-headers and drf-spectacular. Vendor authentication and permission classes are used unchanged on aiodrf views.
Run with Docker¶
From the repository root:
docker compose -f examples/compose.yaml up --build --wait ecosystem-security
docker compose -f examples/compose.yaml exec ecosystem-security python manage.py check
The API is available on http://127.0.0.1:8120. See
container setup for port overrides, required services,
optional profiles, tests and data retention. The commands below run the same
application directly with uv.
Run¶
uv venv
uv pip install --python .venv/bin/python -r pyproject.toml --group test -e ../..
uv run --no-sync python manage.py migrate
uv run --no-sync python manage.py createsuperuser
uv run --no-sync uvicorn project.asgi:application --host 127.0.0.1 --port 8120
uv run --no-sync pytest -q
Set EXAMPLE_ALLOWED_HOSTS when using another hostname. The development key,
SQLite database and HTTP cookies are local settings, not deployment defaults.
Resources and authentication¶
| Route | Integration | Contract |
|---|---|---|
/articles/?title=example |
django-filter and Guardian | The queryset is filtered by object-level view permission before pagination. Model permissions alone do not disclose objects. |
/notes/ |
rules | Owner predicates authorize detail actions. The queryset separately restricts list visibility to the owner. |
/djoser/token/login/, /identity/token/ |
Djoser and DRF tokens | Exchange username/password for auth_token; send Authorization: Token <token>. |
/dj-rest-auth/login/, /identity/cookie/ |
dj-rest-auth and SimpleJWT | Login sets the vendor JWT cookie. Cookie-authenticated writes require an explicit CSRF policy in a deployment. |
/_allauth/app/v1/auth/login, /identity/allauth/ |
allauth headless | Send the returned meta.session_token as X-Session-Token. |
/oauth/, /identity/oauth/ |
django-oauth-toolkit | The identity endpoint requires an unexpired bearer token with the read scope. Register an application in the admin and use the vendor authorization flow. |
/schema/, /docs/ |
drf-spectacular | OpenAPI schema and Swagger UI; documentation visibility is a deployment decision. |
/admin/ |
Django admin | Manage users and model permissions with Django's normal permission system. |
For a non-superuser, assign the required demo.*_article model permissions
through the admin. Grant object permissions through guardian.shortcuts.assign_perm
or create an article through the API, which grants its creator view/change/delete
permissions. The source deliberately keeps that business rule in perform_create.
curl -u reader:local-password http://127.0.0.1:8120/articles/
curl -u reader:local-password -H 'Content-Type: application/json' \
-d '{"title":"Example","sensitive_note":"not returned"}' \
http://127.0.0.1:8120/articles/
Transaction and audit boundaries¶
perform_create, perform_update and perform_destroy are synchronous hooks.
aiodrf runs them in its thread-sensitive worker. set_actor is entered after
DRF authentication, so a token-authenticated user is recorded correctly; Django
middleware alone sees a different authentication stage. The write and permission
assignment use one database transaction. Sensitive content is write-only in the
API, excluded from history and masked in the audit log. Decide retention and
access policies before using either log in production.
The tests use real tokens and ASGI requests. They cover denied modifications, hidden objects, owner-scoped lists, masked audit data, provider login and CORS. Production OAuth consent, federation, email delivery and cross-origin cookie security need to be configured and verified in your deployment. See the security guidance.