fix: add documentation on sealing sessions#625
Conversation
Greptile SummaryThis PR documents the v5→v6 migration path for users who passed The one pre-existing issue surfaced by touching Confidence Score: 5/5Safe to merge — the code change and tests are correct; the only finding is a pre-existing security hygiene gap. The src/workos/session.py — pre-existing
|
| Filename | Overview |
|---|---|
| src/workos/session.py | Makes user a required parameter in seal_session_from_auth_response, removes the conditional inclusion logic; correct fix, but pre-existing JWT validation gaps (no iss, aud disabled) remain in the touched file. |
| tests/test_session.py | Tests updated to pass required user arg; test_seal_without_optional_fields correctly renamed to test_seal_without_impersonator and assertions updated to match new behavior. |
| docs/V6_MIGRATION_GUIDE.md | Adds comprehensive migration section for session= removal from auth helpers, including examples for seal_session_from_auth_response and seal_data; checklist and search regex updated accordingly. |
Sequence Diagram
sequenceDiagram
participant App
participant WorkOSClient
participant seal_session_from_auth_response
participant Cookie
Note over App,Cookie: v6 explicit sealing flow
App->>WorkOSClient: authenticate_with_code(code=code)
WorkOSClient-->>App: AuthResponse(access_token, refresh_token, user, impersonator)
App->>seal_session_from_auth_response: access_token, refresh_token, user.to_dict(), impersonator?, cookie_password
seal_session_from_auth_response-->>App: sealed_session (Fernet encrypted)
App->>Cookie: Set sealed_session cookie
Note over App,Cookie: Later — session refresh
App->>WorkOSClient: load_sealed_session(session_data, cookie_password)
WorkOSClient-->>App: Session object
App->>Session: refresh()
Session-->>App: RefreshWithSessionCookieSuccessResponse(sealed_session, ...)
Comments Outside Diff (1)
-
src/workos/session.py, line 227-233 (link)JWT
issandaudclaims not validatedBoth
Session.authenticate()(line 227) andAsyncSession.authenticate()(line 408) decode the access token withoptions={"verify_aud": False}and noissconstraint, leaving two of the three critical JWT claims unvalidated. A token signed by the correct JWKS key but issued for a different issuer or audience would be accepted. The team's security policy requires that bothissandaudare validated before use.decoded = jwt.decode( session["access_token"], signing_key.key, algorithms=self._JWK_ALGORITHMS, options={"verify_aud": False}, # aud skipped # no issuer= / options["verify_iss"] set leeway=self._client._jwt_leeway, )
Consider passing the expected
issuerand re-enabling audience verification (or explicitly setting the expected audience), or add a comment explaining why these validations are intentionally skipped for this endpoint.Rule Used: JWTs should always be validated before use and the... (source)
Reviews (1): Last reviewed commit: "`user` is not optional" | Re-trigger Greptile
This PR adds documentation/guidance around applications that previously passed
session=intoauthenticate_with_code()orauthenticate_with_refresh_token().userwas also erroneously set toOptionalin these helper methods.