Django Session Auth¶
Docs: https://docs.djangoproject.com/en/dev/topics/auth
For this auth to work, you will need to:
Properly add and configure
django.contrib.sessions.middleware.SessionMiddlewaremiddlewareProperly add and configure
django.contrib.auth.middleware.AuthenticationMiddlewaremiddlewareSet correct auth settings, like enabling
django.contrib.authapp
Make sure to follow the default Django’s guide on setting up the regular Django auth before going further.
Requiring auth¶
Note
Current user will always be accessible as self.request.user.
Read more: https://docs.djangoproject.com/en/stable/topics/auth/default/
We provide two classes to require Django session auth in your API:
DjangoSessionSyncAuthfor sync viewsDjangoSessionAsyncAuthfor async views
Example, how to use the auth class and how to get self.request.user:
1from django.contrib.auth.models import User
2
3from dmr import Controller
4from dmr.plugins.pydantic import PydanticSerializer
5from dmr.security import AuthenticatedHttpRequest
6from dmr.security.django_session import DjangoSessionSyncAuth
7
8
9class APIController(Controller[PydanticSerializer]):
10 request: AuthenticatedHttpRequest[User]
11 auth = (DjangoSessionSyncAuth(),)
12
13 def get(self) -> str:
14 # Let's test that `User` has the correct type:
15 assert self.request.user.username
16 return 'authed'
17
OpenAPI Schema
Preview openapi.json
{
"components": {
"schemas": {
"ErrorDetail": {
"description": "Base schema for error details description.",
"properties": {
"loc": {
"items": {
"anyOf": [
{
"type": "integer"
},
{
"type": "string"
}
]
},
"title": "Loc",
"type": "array"
},
"msg": {
"title": "Msg",
"type": "string"
},
"type": {
"title": "Type",
"type": "string"
}
},
"required": [
"msg"
],
"title": "ErrorDetail",
"type": "object"
},
"ErrorModel": {
"description": "Default error response schema.\n\nCan be customized.\nSee :ref:`customizing-error-messages` for more details.",
"properties": {
"detail": {
"items": {
"$ref": "#/components/schemas/ErrorDetail"
},
"title": "Detail",
"type": "array"
}
},
"required": [
"detail"
],
"title": "ErrorModel",
"type": "object"
}
},
"securitySchemes": {
"csrf": {
"description": "CSRF protection",
"in": "cookie",
"name": "csrftoken",
"type": "apiKey"
},
"django_session": {
"description": "Reusing standard Django auth flow for API",
"in": "cookie",
"name": "sessionid",
"type": "apiKey"
}
}
},
"info": {
"title": "Django Modern Rest",
"version": "0.1.0"
},
"openapi": "3.2.0",
"paths": {
"/api/apicontroller/": {
"get": {
"deprecated": false,
"operationId": "getApicontrollerApiApicontroller",
"responses": {
"200": {
"content": {
"application/json": {
"schema": {
"type": "string"
}
}
},
"description": "OK"
},
"401": {
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/ErrorModel"
}
}
},
"description": "Raised when auth was not successful"
},
"403": {
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/ErrorModel"
}
}
},
"description": "Raised when CSRF check failed"
},
"406": {
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/ErrorModel"
}
}
},
"description": "Raised when provided `Accept` header cannot be satisfied"
},
"422": {
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/ErrorModel"
}
}
},
"description": "Raised when returned response does not match the response schema"
}
},
"security": [
{
"csrf": [],
"django_session": []
}
]
}
}
}
}
Note
Using any of these classes would also automatically enable CSRF checks
for this view. Because it is not secure to use Django
session auth without CSRF checks.
Reusing pre-existing views¶
We provide several pre-existing views to get Django session cookie. So, users won’t have to write tons of boilerplate code.
We provide two Reusable controllers to obtain Django session cookie:
DjangoSessionSyncControllerfor sync controllersDjangoSessionAsyncControllerfor async controllers
To use them, you will need to:
Provide actual types for serializer, request model, and response body
Redefine
convert_auth_payload()to convert your request model into the kwargs ofdjango.contrib.auth.authenticate()to authenticate your requestRedefine
make_api_response()to return the response in the format of your choice
1from typing_extensions import override
2
3from dmr.plugins.pydantic import PydanticSerializer
4from dmr.security.django_session.views import (
5 DjangoSessionPayload,
6 DjangoSessionResponse,
7 DjangoSessionSyncController,
8)
9
10
11class SessionSyncController(
12 DjangoSessionSyncController[
13 PydanticSerializer,
14 DjangoSessionPayload,
15 DjangoSessionResponse,
16 ],
17):
18 @override
19 def convert_auth_payload(
20 self,
21 payload: DjangoSessionPayload,
22 ) -> DjangoSessionPayload:
23 return payload
24
25 @override
26 def make_api_response(self) -> DjangoSessionResponse:
27 return {'user_id': str(self.request.user.pk)}
28
Run result
$ curl http://127.0.0.1:8000/api/auth/ -D - -X POST -d '{"username": "test_user", "password": "password"}' -H 'Content-Type: application/json'
HTTP/1.1 200 OK
date: Sun, 26 Apr 2026 21:10:58 GMT
server: uvicorn
Content-Type: application/json
X-Frame-Options: DENY
Vary: Accept-Language, Cookie
Content-Language: en
Content-Length: 15
X-Content-Type-Options: nosniff
Referrer-Policy: same-origin
Cross-Origin-Opener-Policy: same-origin
Set-Cookie: csrftoken=M8fNP1LozYgaMVIOSNhxMgeBPPk1OpLp; expires=Sun, 25 Apr 2027 21:10:58 GMT; Max-Age=31449600; Path=/; SameSite=Lax
Set-Cookie: sessionid=z7tnl5s5ega117lm95aywoz2inp02be9; expires=Sun, 10 May 2026 21:10:58 GMT; HttpOnly; Max-Age=1209600; Path=/; SameSite=Lax
{"user_id":"1"}
OpenAPI Schema
Preview openapi.json
{
"components": {
"schemas": {
"DjangoSessionPayload": {
"description": "Payload for default version of a django session request body.\n\nIs also used as kwargs for :func:`django.contrib.auth.authenticate`.",
"properties": {
"password": {
"title": "Password",
"type": "string"
},
"username": {
"title": "Username",
"type": "string"
}
},
"required": [
"username",
"password"
],
"title": "DjangoSessionPayload",
"type": "object"
},
"DjangoSessionResponse": {
"description": "Default response type for django session endpoint.",
"properties": {
"user_id": {
"title": "User Id",
"type": "string"
}
},
"required": [
"user_id"
],
"title": "DjangoSessionResponse",
"type": "object"
},
"ErrorDetail": {
"description": "Base schema for error details description.",
"properties": {
"loc": {
"items": {
"anyOf": [
{
"type": "integer"
},
{
"type": "string"
}
]
},
"title": "Loc",
"type": "array"
},
"msg": {
"title": "Msg",
"type": "string"
},
"type": {
"title": "Type",
"type": "string"
}
},
"required": [
"msg"
],
"title": "ErrorDetail",
"type": "object"
},
"ErrorModel": {
"description": "Default error response schema.\n\nCan be customized.\nSee :ref:`customizing-error-messages` for more details.",
"properties": {
"detail": {
"items": {
"$ref": "#/components/schemas/ErrorDetail"
},
"title": "Detail",
"type": "array"
}
},
"required": [
"detail"
],
"title": "ErrorModel",
"type": "object"
}
},
"securitySchemes": {}
},
"info": {
"title": "Django Modern Rest",
"version": "0.1.0"
},
"openapi": "3.2.0",
"paths": {
"/api/sessionsynccontroller/": {
"post": {
"deprecated": false,
"operationId": "postSessionsynccontrollerApiSessionsynccontroller",
"requestBody": {
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/DjangoSessionPayload"
}
}
},
"description": "Payload for default version of a django session request body.\n\nIs also used as kwargs for :func:`django.contrib.auth.authenticate`.",
"required": true
},
"responses": {
"200": {
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/DjangoSessionResponse"
}
}
},
"description": "OK",
"headers": {
"Set-Cookie: csrftoken": {
"description": "CSRF protection.",
"required": true,
"schema": {
"example": "csrftoken=123",
"type": "string"
}
},
"Set-Cookie: sessionid": {
"required": true,
"schema": {
"example": "sessionid=123",
"type": "string"
}
}
}
},
"400": {
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/ErrorModel"
}
}
},
"description": "Raised when request components cannot be parsed"
},
"401": {
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/ErrorModel"
}
}
},
"description": "Unauthorized"
},
"406": {
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/ErrorModel"
}
}
},
"description": "Raised when provided `Accept` header cannot be satisfied"
},
"422": {
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/ErrorModel"
}
}
},
"description": "Raised when returned response does not match the response schema"
}
},
"summary": "By default cookies are acquired on post."
}
}
}
}
Any further customizations are also possible.
CSRF¶
When a user logs in through these controllers, Django automatically rotates
the CSRF token and includes a csrftoken cookie in the login response
(alongside the session cookie).
Clients making subsequent non-safe requests (POST, PUT, PATCH,
DELETE) to session-protected endpoints must send this token back via the
X-CSRFToken request header.
Note
When CSRF_USE_SESSIONS is True, Django stores the CSRF token
in the session instead of a cookie. In that case no csrftoken cookie
appears in the login response — the token is already embedded in the
session used for authentication.
API Reference¶
- class dmr.security.django_session.auth.DjangoSessionSyncAuth(security_scheme_name: str = 'django_session', csrf_scheme_name: str = 'csrf')[source]¶
Reuses Django’s regular session auth for the API.
This class is used for sync endpoints.
- __call__(endpoint: Endpoint, controller: Controller[BaseSerializer]) Self | None[source]¶
Does check for the existing request user.
- authenticate(endpoint: Endpoint, controller: Controller[BaseSerializer]) Self | None[source]¶
Override this method to provide other authentication logic.
For example: checking that user is staff / superuser.
- provide_response_specs(metadata: EndpointMetadata, controller_cls: type[Controller[BaseSerializer]], existing_responses: Mapping[HTTPStatus, ResponseSpec]) list[ResponseSpec]¶
Provides responses that can happen when user is not authed.
- property security_schemes: dict[str, SecurityScheme | Reference]¶
Provides a security schema definition.
- class dmr.security.django_session.auth.DjangoSessionAsyncAuth(security_scheme_name: str = 'django_session', csrf_scheme_name: str = 'csrf')[source]¶
Reuses Django’s regular session auth for the API.
This class is used for async endpoints.
- async __call__(endpoint: Endpoint, controller: Controller[BaseSerializer]) Self | None[source]¶
Does check for the existing request user.
- async authenticate(endpoint: Endpoint, controller: Controller[BaseSerializer]) Self | None[source]¶
Override this method to provide other authentication logic.
For example: checking that user is staff / superuser.
- provide_response_specs(metadata: EndpointMetadata, controller_cls: type[Controller[BaseSerializer]], existing_responses: Mapping[HTTPStatus, ResponseSpec]) list[ResponseSpec]¶
Provides responses that can happen when user is not authed.
- property security_schemes: dict[str, SecurityScheme | Reference]¶
Provides a security schema definition.