Skip to content

feat: enforce upstream IdP session_expiry ceiling (IPSIE SL1) - #120

Merged
kishore7snehil merged 9 commits into
mainfrom
feat/ipsie-session-expiry
Jul 1, 2026
Merged

feat: enforce upstream IdP session_expiry ceiling (IPSIE SL1)#120
kishore7snehil merged 9 commits into
mainfrom
feat/ipsie-session-expiry

Conversation

@kishore7snehil

Copy link
Copy Markdown
Contributor

📋 Changes

This PR adds enforcement of the IPSIE SL1 session_expiry claim to auth0-server-python — an absolute Unix-epoch ceiling an upstream IdP can assert on how long an Auth0 app session may live. The SDK reads the claim at login, stamps it on internal.session_expires_at, and enforces it lazily on every read.

✨ Features

  • Login-time enforcement: complete_interactive_login reads session_expiry/iat from the verified ID token claims and stamps internal.session_expires_at on the persisted session. A login whose ceiling is already in the past is rejected with SessionExpiredError rather than persisted; the spent transaction is cleaned up before raising since its authorization code cannot be reused.
  • Read-time enforcement: get_session() / get_user() return None (and delete the session) once the ceiling is reached; get_access_token() raises AccessTokenError(SESSION_EXPIRED). A 30s negative clock-skew leeway is applied so the SDK never serves a session the platform has already revoked.
  • Refresh preservation: The ceiling stamped at login is preserved across refresh-token grants — the platform does not re-emit session_expiry on a refresh, so the original ceiling is never overwritten or erased.

🔧 API Changes

  • New SessionExpiredError — flow-agnostic, carries code == "session_expired"
  • UserClaims.session_expiry: Optional[int] and InternalStateData.session_expires_at: Optional[int]

📖 Documentation

  • Updated README.md and examples/RetrievingData.md with usage, the upgrade null-check note, leeway behavior, and refresh preservation

🧪 Testing

  • This change adds test coverage
  • This change has been tested on the latest version of the platform/language

Contributor Checklist

…laim extraction

Add a login-time lockout guard to complete_interactive_login: when the upstream
IdP asserts a session_expiry ceiling already in the past at login (compared
against the ID token iat with the same 30s leeway as read-time enforcement),
raise the new flow-agnostic SessionExpiredError instead of persisting an
already-expired session. A missing claim stays a no-op, preserving existing
behavior.

Generalize extract_session_expiry into extract_epoch_claim(claims, name),
reused for both session_expiry and iat, and rename the ceiling predicates to
is_session_ceiling_reached (read-time) and is_session_ceiling_in_past (login).

Document the login rejection in the README, RetrievingData guide, and the
ipsie-webapp example.
…m boundary

The signature-verified, Auth0-issued ID token has already been validated
upstream (the platform refuses to emit a malformed session_expiry), so the
SDK reads it like every other operational claim instead of running a bespoke
validator. Removes State.extract_epoch_claim and reads session_expiry/iat
with a plain .get() at both extraction sites; the None guards in the ceiling
comparison functions still deliver the absent/null "no ceiling" safe default.

Production-reachable inputs (absent/null, clean integer) are unchanged; only
unreachable malformed values change behavior, now failing closed rather than
being silently accepted.
Delete the transaction before raising SessionExpiredError at the login
guard — the authorization code was already exchanged, so the transaction
is spent and cannot be reused. Also treat iat=0 as a valid issued-at
reference (use `is not None` rather than truthiness) in the ceiling
lapsed check.
@kishore7snehil
kishore7snehil requested a review from a team as a code owner June 11, 2026 19:03
Move the session_expiry plausibility check (type, range, ms-vs-seconds
upper bound) into the UserClaims pydantic validator so both login
extraction paths read an already-sanitized value. Point the example doc
to official Auth0 docs for the Post-Login Action setup instead of
embedding the snippet.
…g error

Address PoC review findings carried into the implementation:

- Stop reading session_expiry/iat from the unverified userinfo branch in
  complete_interactive_login; derive the ceiling only from the
  signature-and-issuer-verified ID token. Add a regression test that drives
  the userinfo branch and asserts no ceiling is persisted.
- Raise the flow-agnostic SessionExpiredError at the get_access_token
  ceiling check so login and read-time enforcement use one error type.
- Import field_validator in auth_types so the UserClaims sanitizer loads.
- Correct the refresh-path comment in helpers to describe carrying the
  pinned ceiling forward rather than a non-existent overwrite guard.
@nandan-bhat

Copy link
Copy Markdown
Contributor

LGTM

@kishore7snehil
kishore7snehil merged commit 3ff30aa into main Jul 1, 2026
9 checks passed
@kishore7snehil
kishore7snehil deleted the feat/ipsie-session-expiry branch July 1, 2026 03:32
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

2 participants