π JWT in DuckΒΆ
Duck provides first-class JWT support through:
request.JWT(a JWT payload store attached to every request)duck.http.middlewares.contrib.JWTMiddleware(token extraction + delivery)duck.contrib.jwt(encoding/decoding helpers)
How JWT Works in DuckΒΆ
Every incoming request gets a
request.JWTstore.JWTMiddlewarereads the access token from cookie or header (based on settings).The token is decoded lazily when
request.JWTis accessed.Your view/component updates JWT claims using
request.JWT.If claims changed (or token expired / refresh token supplied), middleware re-issues access + refresh tokens in the response.
Request JWT Store (request.JWT)ΒΆ
Duck uses JWTStore (default engine: duck.http.jwt.engine) for payload access and mutation.
Common operations:
Read a claim:
request.JWT.get("key")orrequest.JWT["key"]Set a claim:
request.JWT["key"] = valueorrequest.JWT.set("key", value)Remove a claim:
request.JWT.delete("key")Clear all claims:
request.JWT.clear()Check dirty state:
request.JWT.needs_update()Check expiry:
request.JWT.is_expired()
Notes:
The store is lazy-loaded.
If no token is present, store starts empty (not an error).
If you encode manually,
expmust exist in payload.Expiry can be controlled with
set_expiry(...)/reset_expiry().
JWT Middleware BehaviorΒΆ
JWTMiddleware is included in Duckβs recommended middleware list.
Request phaseΒΆ
Resolves transport via
JWT_TRANSPORT(cookieorheader).Reads access token from configured cookie/header.
Attaches raw token to
request.JWTfor lazy decode.
Response phaseΒΆ
If JWT changed, expired, or refresh token exists, middleware re-issues tokens.
Refresh token (if provided) is validated and merged safely.
New access + refresh tokens are written back using configured transport.
SettingsΒΆ
Core settings used by JWT:
JWT_SECRET_KEY(falls back toSECRET_KEY)JWT_ALGORITHM(default:HS256)JWT_ACCESS_LIFETIME(default:3600seconds)JWT_REFRESH_LIFETIME(default:7 * 24 * 3600seconds)JWT_ENGINE(default:duck.http.jwt.engine)
Transport settings:
JWT_TRANSPORT:cookieorheader(default:cookie)
Cookie transport:
JWT_COOKIE_NAME(default:jwt)JWT_REFRESH_COOKIE_NAME(default:jwt-refresh)JWT_COOKIE_HTTPONLY(default:True)JWT_COOKIE_SECURE(default:False)JWT_COOKIE_SAMESITE(default:Lax)JWT_COOKIE_DOMAIN(defaults to Duck server domain)
Header transport:
JWT_HEADER_NAME(default:X-JWT-Token)JWT_REFRESH_HEADER_NAME(default:X-Refresh-JWT-Token)
Low-level JWT HelpersΒΆ
duck.contrib.jwt exposes:
encode_token(payload, token_type="access")decode_token(token, verify_expiry=True)issue_token_pair(payload)JWTError,JWTExpired,JWTInvalid
Use these for custom token flows when needed.
Lively / WebSocket State SyncΒΆ
During Lively interactions, request state is reused.
If JWT/session/CSRF state changes, Duck queues a browser-state sync response so sensitive updates (including HttpOnly cookies) are applied through a secure follow-up fetch.
Minimal ExampleΒΆ
from duck.http.response import HttpResponse
def login_like_view(request):
request.JWT["user_id"] = "42"
request.JWT["role"] = "member"
return HttpResponse("ok")
On response, JWTMiddleware issues updated access/refresh tokens.