feat(session): add require_user_session and warn about short JWT HMAC keys - #275
Merged
Merged
Conversation
… keys get_session, RequiredSession and UserSessionDep only check that a session exists, so an anonymous session created by a cart or CSRF write passes them. require_user_session (AuthenticatedSession) also answers 401 when session.user is None. UserSessionDep keeps its behaviour until 0.4.0. JWTTokenSerializer now emits one UserWarning when it is built with a secret_key shorter, in UTF-8 bytes, than the HMAC hash output that RFC 7518 section 3.2 requires (48 bytes for HS384, 64 for HS512). Closes #114 Closes #116
This was referenced Sep 27, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Closes #114. Closes #116.
#114:
require_user_sessionget_session,RequiredSessionandUserSessionDeponly check that a session exists. UnderFastAPICacheXSessionMiddleware, any visitor who reaches a route that writes torequest.session(a cart, a CSRF value) gets an anonymous session withuser=None, and that session passes all three.require_user_sessiondependency. It builds onget_session, so theSessionBearerOpenAPI scheme still appears.401 Authentication requiredwithWWW-Authenticate: Bearerwhen there is no session orsession.user is None.AuthenticatedSession.fastapi_cachex.sessionandfastapi_cachex.UserSessionDepis unchanged. A comment and the docs say it still accepts anonymous sessions until 0.4.0.#116: short JWT HMAC keys
SessionConfigrequires 32 characters, but HS384 and HS512 need 48 and 64 bytes (RFC 7518 §3.2).JWTTokenSerializer.__init__now emits oneUserWarningwhen the key is shorter than the hash output.stacklevelpoints at the code that constructed the serializer.secret_keyandjwt_algorithmand suggests a fix.UserWarning. It matches the existingcookie_same_sitemisconfiguration warning and is the base class of PyJWT'sInsecureKeyLengthWarning. It cannot beInsecureKeyLengthWarningitself, becausejwt_modulemay be a non-PyJWT implementation.warnings.catch_warnings()around everyencode/decode, which mutates process-global warning state on each request. The docs mention the PyJWT warning instead.Docs
get_sessionvsrequire_user_session, with an example;require_user_session,UserSessionDepandAuthenticatedSession;Tests
test_require_user_session_rejects_anonymous_sessionsruns end to end throughFastAPICacheXSessionMiddleware. With no session it gets 401. After an anonymous cart write,RequiredSessionpasses butAuthenticatedSessiongets 401 withWWW-Authenticate: Bearer. With a user session, it succeeds.test_jwt_serializer_warns_once_about_a_short_hmac_keycovers these cases, using the stub JWT module, so no PyJWT import:écharacters (64 bytes) under HS512.écase;stacklevel=2fails only the two "warns" cases, via the filename assertion.uv run pytest: 807 passed, 190 skipped. The live Redis/Memcached tests were skipped because no test servers were configured for this run; CI runs them.pre-commit run --all-files(withSKIP=uv-lock): clean.CHANGELOG
Added:
Security: