π Authentication in DuckΒΆ
Duck ships authentication helpers in duck.contrib.auth with two backends:
session(default): stores auth state inrequest.SESSIONjwt: stores auth state inrequest.JWT
Helpers support both sync and async usage.
Available HelpersΒΆ
Sync:
authenticate(request, username, password)login(request, user=None, user_id=None, backend=None)logout(request, backend=None)get_user_id(request, backend=None)get_user_from_session(request)get_user_from_jwt(request)set_default_auth_backend("session" | "jwt")
Async:
async_authenticate(...)async_login(...)async_logout(...)async_get_user_from_session(...)async_get_user_from_jwt(...)
Errors:
duck.contrib.auth.exceptions.AuthenticationError
How Authentication WorksΒΆ
1) Credential verificationΒΆ
authenticate(...):
Uses Djangoβs
get_user_model()Looks up user by
User.USERNAME_FIELDVerifies password with Django hashers
Rejects inactive users
Raises
AuthenticationErroron failure
2) Login persistenceΒΆ
login(...) stores:
_auth_user_id_auth_backend
Storage target depends on backend:
sessionbackend βrequest.SESSIONjwtbackend ->request.JWT
3) User resolutionΒΆ
get_user_id(...)helps with fast login when user ID is already known.get_user_from_session(...)reads_auth_user_idfrom sessionget_user_from_jwt(...)reads_auth_user_idfrom JWT claimsAll these functions return
Noneif user no longer exists
4) Logout behaviorΒΆ
Session backend: clears session store
JWT backend: clears JWT claims in
request.JWT
For JWT flows, client-side token discard/invalidation policy is still your responsibility.
Backend SelectionΒΆ
login, logout, and async equivalents use:
explicit
backendargument if providedotherwise the process-wide default backend
Default backend starts as session.
You can change it with:
from duck.contrib.auth import set_default_auth_backend
set_default_auth_backend("jwt")
RequirementsΒΆ
Most auth helpers rely on Django auth models/ORM.
For JWT auth persistence, keep
JWTMiddlewareenabled so tokens can be read and re-issued correctly.
Session Backend ExampleΒΆ
from duck.contrib.auth import authenticate, login, get_user_from_session
from duck.contrib.auth.exceptions import AuthenticationError
from duck.http.response import HttpResponse
def sign_in(request):
try:
user = authenticate(request, "user@example.com", "secret")
except AuthenticationError:
return HttpResponse("invalid credentials", status_code=401)
# Login user and return response.
login(request, user, backend="session")
return HttpResponse("signed in")
JWT Backend ExampleΒΆ
from duck.contrib.auth import authenticate, login, get_user_from_jwt
from duck.contrib.auth.exceptions import AuthenticationError
from duck.http.response import HttpResponse
def sign_in_jwt(request):
try:
user = authenticate(request, "user@example.com", "secret")
except AuthenticationError:
return HttpResponse("invalid credentials", status_code=401)
# Login user and return response.
login(request, user, backend="jwt")
return HttpResponse("signed in")
JWTMiddleware then writes updated tokens in the response.