Hello team! I stumbled across a possible bug while experimenting with AuthKit and I wanted to share the insights with you. This report is AI-curated and I hope it's useful and complete. Please let me know if you need any other information from my side. Thank you.
Summary
Refreshing a sealed AuthKit session via the documented load_sealed_session(...).refresh() flow always fails. The underlying /user_management/authenticate call returns 200 OK, but Session.refresh() then raises KeyError('sealed_session') internally, swallows it, and returns a RefreshWithSessionCookieErrorResponse whose reason is the literal string "'sealed_session'" — not a member of AuthenticateWithSessionCookieFailureReason. In a cookie-session web app this logs the user out the first time their access token needs refreshing.
Environment: workos 8.0.0 · Python 3.14.4 · macOS 15.7.7 · WorkOS Sandbox
Reproduction
Self-contained — needs only WorkOS credentials and one user, read from env:
import os
from workos import WorkOSClient
from workos.session import seal_data
client = WorkOSClient(
api_key=os.environ["WORKOS_API_KEY"],
client_id=os.environ["WORKOS_CLIENT_ID"],
)
cookie_password = os.environ["WORKOS_COOKIE_PASSWORD"] # any string >= 32 chars
# A valid, unused refresh token. Minted here via the password grant (any WorkOS
# user with password auth enabled); or substitute an existing refresh token.
refresh_token = client.user_management.authenticate_with_password(
email=os.environ["WORKOS_USER_EMAIL"],
password=os.environ["WORKOS_USER_PASSWORD"],
).refresh_token
# refresh() only needs a refresh_token + a truthy user in the sealed payload to
# reach the network call, and it ignores access-token expiry — so this
# reproduces immediately, no waiting required.
sealed = seal_data({"refresh_token": refresh_token, "user": {"id": "x"}}, cookie_password)
session = client.user_management.load_sealed_session(
session_data=sealed, cookie_password=cookie_password,
)
result = session.refresh()
print(result.authenticated, repr(result.reason))
# -> False "'sealed_session'"
Expected behaviour: a RefreshWithSessionCookieSuccessResponse with a new sealed_session, or a documented failure reason.
Actual behaviour: authenticated=False, reason="'sealed_session'".
Root cause
In src/workos/session.py, Session.refresh() (~lines 312–391 on main):
- POSTs a
refresh_token grant with
session={"seal_session": True, "cookie_password": ...} → HTTP 200.
- Reads
auth_response["sealed_session"] via a hard key access (~lines 361, 377).
- The 200 body has no
sealed_session — its keys are
['access_token', 'authentication_method', 'refresh_token', 'user'] — so this
raises KeyError('sealed_session').
- The surrounding
except Exception (~line 388) maps it with
_map_refresh_exception_to_reason, which has no KeyError branch and falls
back to return str(exc) → "'sealed_session'".
Suggested fix
Guard the read with auth_response.get("sealed_session") and return a documented reason (or raise a typed error) when it is absent; and confirm the refresh_token grant request actually elicits sealed_session from the API.
Workaround
Refresh by hand with the typed method and re-seal the cookie, instead of session.refresh():
from workos.session import seal_data, unseal_data
stored = unseal_data(sealed_cookie_value, COOKIE_PASSWORD)
refreshed = client.user_management.authenticate_with_refresh_token(
refresh_token=stored["refresh_token"],
)
new_sealed_cookie = seal_data(
{
"access_token": refreshed.access_token,
"refresh_token": refreshed.refresh_token,
"user": refreshed.user.to_dict(),
"impersonator": refreshed.impersonator.to_dict() if refreshed.impersonator else None,
},
COOKIE_PASSWORD,
)
Hello team! I stumbled across a possible bug while experimenting with AuthKit and I wanted to share the insights with you. This report is AI-curated and I hope it's useful and complete. Please let me know if you need any other information from my side. Thank you.
Summary
Refreshing a sealed AuthKit session via the documented
load_sealed_session(...).refresh()flow always fails. The underlying/user_management/authenticatecall returns200 OK, butSession.refresh()then raisesKeyError('sealed_session')internally, swallows it, and returns aRefreshWithSessionCookieErrorResponsewhosereasonis the literal string"'sealed_session'"— not a member ofAuthenticateWithSessionCookieFailureReason. In a cookie-session web app this logs the user out the first time their access token needs refreshing.Environment: workos 8.0.0 · Python 3.14.4 · macOS 15.7.7 · WorkOS Sandbox
Reproduction
Self-contained — needs only WorkOS credentials and one user, read from env:
Expected behaviour: a
RefreshWithSessionCookieSuccessResponsewith a newsealed_session, or a documented failurereason.Actual behaviour:
authenticated=False,reason="'sealed_session'".Root cause
In
src/workos/session.py,Session.refresh()(~lines 312–391 onmain):refresh_tokengrant withsession={"seal_session": True, "cookie_password": ...}→ HTTP 200.auth_response["sealed_session"]via a hard key access (~lines 361, 377).sealed_session— its keys are['access_token', 'authentication_method', 'refresh_token', 'user']— so thisraises
KeyError('sealed_session').except Exception(~line 388) maps it with_map_refresh_exception_to_reason, which has noKeyErrorbranch and fallsback to
return str(exc)→"'sealed_session'".Suggested fix
Guard the read with
auth_response.get("sealed_session")and return a documented reason (or raise a typed error) when it is absent; and confirm therefresh_tokengrant request actually elicitssealed_sessionfrom the API.Workaround
Refresh by hand with the typed method and re-seal the cookie, instead of
session.refresh():