TGViewer
Находки в опенсорсе: Python Находки в опенсорсе: Python @opensource_findings_python · 1.06K subscribers
Post #290 343
🚀 New issue to wemake-services/django-modern-rest by @vyhuholl
📝 Reusable controllers to issue JWT tokens as cookies (#1290)


FEATURE

Thesis

Follow-up to #1287. That PR added CookieJWTSyncAuth / CookieJWTAsyncAuth, which read a JWT from a cookie. Nothing in the framework writes one, so the issuing half is still left to every user.

docs/pages/auth/jwt.rst currently carries a .. todo:: in place of an example, and this issue is that todo.

What is needed
1. Obtain: authenticate and set the access and refresh cookies
2. Refresh: read the refresh token from its cookie and rotate both
3. Log out: clear both cookies, ideally blocklisting the access token (there is no logout controller today at all)

The design obstacle

This is the part that needs a decision, and it is why the todo is still a todo rather than a patch.

Cookie values are only known at request time, but both ways of declaring cookies fix them at decoration time:

@modify(cookies=...) takes NewCookie instances, and ModifyEndpointPayload.actionable_cookies() returns exactly those objects. Static values only.
@validate takes ResponseSpec(cookies=...), which accepts only CookieSpec, that is a description and not a value. Runtime values then go through self.to_response(..., cookies={...: NewCookie(value=...)}).

The second one works, and it is what a hand-written controller does today. But in a reusable controller the decorator runs once, on the base class. The cookie names and flags would be frozen there, and a subclass could only change them by redefining post completely, which removes the reason to have a reusable controller in the first place.

Note that per-subclass data does already reach endpoint metadata: Controller.__init_subclass__ builds an Endpoint per concrete subclass, and ResponseSpecProvider.provide_response_specs receives controller_cls. So a hook is feasible. The open question is its shape, not whether it can exist.

Open questions
• Where do the cookie names and flags come from? ClassVars on the controller like the existing jwt_* settings, dmr settings, or a dedicated spec object?
• Should the tokens still appear in the response body? Putting them in both places is convenient and undoes the point of httponly.
• Does logout blocklist the access token, or stay transport-only?
• How is Set-Cookie represented in the generated OpenAPI schema when the names are configurable?

Requirements for whatever we build
httponly=True and secure=True by default, and samesite no weaker than 'lax'
• The refresh cookie scoped by path to the refresh endpoint, so it is not sent to the rest of the API
• Cookie names matching the auth side, which defaults to DEFAULT_ACCESS_COOKIE (access_token) and DEFAULT_REFRESH_COOKIE (refresh_token) in dmr/security/jwt/cookie.py
• Sync and async variants, like every other controller here
• Working together with the CSRF check in CookieJWTSyncAuth
• The .. todo:: in docs/pages/auth/jwt.rst replaced by a real example

Reasoning

The cookie flags are the entire security surface of this flow. An example is copied verbatim far more often than it is read, and a copy that drops httponly hands the token to any XSS on the page. So the docs deliberately ship no example until there is a controller that gets the defaults right.

That is the same reasoning behind ObtainTokensSyncController for the body flow: users should not have to reassemble the security-critical parts.


#feature #help_wanted #django_modern_rest
sent via relator
More from @opensource_findings_python
  1. Sep 23, 2026🚀 New issue to ag2ai/faststream by @IvanKirpichnikov 📝 Feature: Implementation of the `A…
  2. Sep 22, 2026🚀 New issue to faststream-community/zMQTT by @borisalekseev 📝 Mark flaky Artemis test xf…
  3. Sep 17, 2026Помните про https://github.com/ozeranskii/httptap? Я писал о нем давно еще - > тут. Наклеп…
  4. Sep 15, 2026🚀 New issue to wemake-services/django-modern-rest by @sobolevn 📝 `test_custom_union_form…
  5. Sep 13, 2026🚀 New issue to wemake-services/django-modern-rest by @milssky 📝 Changes in benchmarking…
  6. Sep 13, 2026🚀 New issue to wemake-services/django-modern-rest by @sobolevn 📝 Fix `operation_id` defa…
Threads Profile ViewerView any public Threads profile without an account.Open ThreadLook →Writing with AI? Make it sound human.Metric37 rewrites AI drafts so they read naturally. Free AI detector, 1,500 words free.Try Metric37 →