DMR from dj-rest-auth
SkillWeb & browsingMigrate an existing Django auth API from dj-rest-auth to django-modern-rest, moving account flows onto django-allauth headless and rebuilding the transport layer with dmr controllers and auth classes. Use when replacing dj_rest_auth login/logout/registration/password/MFA/social views and their DRF serializers.
Available today. Use it from your connected AI after setup.
No other account needed.
Connect ahel once, and every AI you use reads what you have installed.
Then ask your AI: use the DMR from dj-rest-auth skill
What this skill tells your AI
The instructions your AI receives, as published by wemake-services/django-modern-rest in .agents/skills/dmr-from-dj-rest-auth/SKILL.md and read by ahel’s review.
Overview
Migrate a dj-rest-auth installation to django-modern-rest.
Required docs (always reference first):
- DMR LLM docs: https://django-modern-rest.readthedocs.io/llms-full.txt
- dj-rest-auth docs: https://dj-rest-auth.readthedocs.io
- allauth headless docs: https://docs.allauth.org/en/latest/headless/index.html
- Local map: references/dj-rest-auth-to-dmr-map.md
Read This First
This migration is not shaped like $dmr-from-drf.
dj-rest-auth is a DRF layer on top of django-allauth. We do not
reimplement account management. django-allauth keeps owning registration,
email verification, password reset, social login, MFA, and passkeys through
its headless mode, and django-modern-rest owns your own API surface plus
the auth classes that read allauth's credentials.
Three consequences the user must accept before any code is written:
- Endpoint paths change. allauth headless serves its own
/_allauth/{client}/v1/...routes. Strict path parity is not a goal and usually not achievable. - Request and response payloads change. allauth has its own envelope
(
status,data,meta) and its own error format. - Every API client must be updated. Treat this as a coordinated frontend + backend migration, not a drop-in backend swap.
If the user cannot change clients, stop and say so. A compatibility shim
that re-serves dj-rest-auth paths and payloads is possible but is a
long-lived maintenance burden. Do not build one silently.
Migration Policy
- Default mode:
behavioral parity, nottransport parity. The same things must be possible; the wire format may differ. - Preserve by default: which flows exist, who can call them, what security properties they have, what lands in the database.
- Every path, payload, or status-code change is
approved driftand must be listed explicitly. Never let a drift pass unlisted just because the endpoint "still works". - Never weaken a security property to make a client's life easier. Call it out and let the user decide.
Workflow
1. Inventory the dj-rest-auth surface
- Find
dj_rest_authinINSTALLED_APPSand its URL includes (dj_rest_auth.urls,dj_rest_auth.registration.urls,dj_rest_auth.mfa.urls). - Record every
REST_AUTHsetting in use, they encode real requirements. See the settings table in the local map. - Record every overridden serializer
(
LOGIN_SERIALIZER,REGISTER_SERIALIZER,USER_DETAILS_SERIALIZER, ...). These are where projects hide their custom business rules. - Record which token strategy is active: DRF
authtoken,simplejwtwith headers,simplejwtwith cookies, or session login. - Record whether
django-allauthis already installed and configured, which it usually is.
2. Inventory custom behavior (required gate)
dj-rest-auth is often customized by subclassing. Before mapping anything,
list for each overridden serializer or view:
- extra fields accepted or returned,
- extra validation,
- side effects (signals, analytics, provisioning, audit records).
Side effects are the part most likely to be lost silently. Each one must be re-attached to an allauth signal or to your own controller.
3. Decide the target auth transport (required gate)
Pick one and record it. See the auth table in the local map.
- allauth headless session tokens ->
XSessionTokenSyncAuth - jwt in
Authorizationheader ->HeaderJWTSyncAuth - jwt in cookies ->
CookieJWTSyncAuth - opaque DB tokens ->
HeaderTokenSyncAuthand thedmrtoken app - Django session cookie ->
DjangoSessionSyncAuth
Match the existing security posture. A project on JWT_AUTH_HTTPONLY
cookies must not be silently moved to header tokens readable by JavaScript.
4. Wire allauth headless
- Add
allauth,allauth.account,allauth.headlesstoINSTALLED_APPSandallauth.account.middleware.AccountMiddlewaretoMIDDLEWARE. - Choose the
apporbrowserclient deliberately:appusesX-Session-Token,browseruses session cookies. - Port
ACCOUNT_*settings so the account rules (email verification, unique email, signup fields) stay the same. - Expose allauth's endpoints in your OpenAPI schema with
external_path(), allauth publishes its own specification.
5. Migrate flow by flow
Migrate one flow at a time, in this order, because later flows depend on being able to log in:
- login and session
- logout
- user details
- password change
- password reset
- registration and email verification
- social login
- MFA and passkeys
For each flow: map the endpoint, port custom validation and side effects, update the client, update tests, then run the repository's checks.
6. Rebuild what allauth does not serve
allauth headless has no user-details endpoint. rest_user_details becomes
your own Controller over your user model, with typed DTOs.
This is normal, and it is the right place for project-specific profile
fields that never belonged in an auth library.
7. Translate serializers into typed DTOs
TypedDictis the default for reusable controllers in this project.- Split input and output DTOs when the response carries server-owned fields.
- Never return password fields, tokens the client should not see, or full user objects where the old serializer returned a subset.
- Apply
@sensitive_post_parametersto anything accepting credentials. - Apply
@sensitive_variables()to every method that holds credentials or tokens in its local variables, so they never reach error reports. Async methods need it on each coroutine, sync ones also cover their callees. - Return
NO_STORE_HEADERSfromdmr.securityin@modifyfor any view that issues or accepts credentials.
8. Port token issuing
- If tokens were issued as cookies (
JWT_AUTH_COOKIE), keep them as cookies with the same flags:httponly,secure,samesite, and the refresh cookie'spath. Do not downgrade them. dmrenforces CSRF automatically for cookie-based auth, which replacesJWT_AUTH_COOKIE_USE_CSRF.- Declare every issued cookie with
CookieSpecso response validation and the OpenAPI schema stay honest.
9. Update tests
- Keep one test per flow asserting the same outcome, not the same payload: a user exists, a session works, a password no longer authenticates.
- Add negative-path tests for every declared error response.
- Assert cookie flags explicitly when cookies carry credentials.
A missing
httponlyis a silent security regression that no happy-path test will catch.
10. Validate with repository-native entrypoints
- Run the same commands CI runs.
- Enable
validate_responsesin development and testing.
11. Finish gate
Do not mark a flow done until linters pass, tests pass, the client is updated, and the report is updated.
Translation Rules
- Account business logic belongs to allauth. Do not fork it into controllers.
- Your own domain logic belongs in your own controllers, not in auth hooks.
- Do not keep
dj_rest_author DRF imports in migrated modules. - Do not keep serializer class names that encode DRF transport internals.
- Preserve security properties even when payload format drifts.
Reporting Format (required)
At each checkpoint and at completion, report in 4 sections:
preserved behaviorapproved drift(paths, payloads, statuses, client changes)security posture changesunresolved gaps
security posture changes is separate on purpose. It must state explicitly
when cookie flags, CSRF behavior, token lifetime, or token visibility
to JavaScript changed, even if the user already approved it.
Migration Pitfalls
dj-rest-authlogout has two behaviors depending onSESSION_LOGINand token strategy. Verify what the deployment actually does before mapping it.LOGOUT_ON_PASSWORD_CHANGEsilently invalidates sessions. allauth's behavior differs; check it rather than assuming.OLD_PASSWORD_FIELD_ENABLEDcontrols whether the current password is required. Turning this off during migration is a security regression.- Blindly copying
JWT_AUTH_*settings loses the cookie flags, because they become arguments toNewCookie, not settings. - Custom
REGISTER_SERIALIZERside effects (provisioning, invites, billing) disappear unless re-attached to allauth signals. simplejwtrefresh-token rotation and blacklisting are not automatic indmr. Use thedmrjwt blocklist app if the project relied on it.- Social login callback URLs are provider-registered. Changing the path requires updating provider configuration too.
Output Checklist
- allauth headless is wired and serving the account flows.
- Auth transport chosen deliberately and matching the previous posture.
- User-details and any project-specific endpoints rebuilt as dmr controllers.
- All serializers replaced with typed DTOs; no
dj_rest_authimports remain. - Cookie flags and CSRF behavior preserved or explicitly drift-approved.
- Custom validation and side effects re-attached and tested.
- allauth endpoints represented in the OpenAPI schema.
- Response validation enabled and passing.
- Clients updated for every approved path or payload change.
- Final report emitted in the required 4-section format.
- After green CI, remove
dj-rest-auth, anddjangorestframeworkif nothing else needs it, from project dependencies.
Signals
- GitHub stars
- 1k
- Forks
- 190
- Last commit
- Sep 2026
Advanced
- Catalog kind
- skill
- Gateway key
dmr-from-dj-rest-auth- Source
- github.com/wemake-services/django-modern-rest