You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Copy file name to clipboardExpand all lines: README.md
+6Lines changed: 6 additions & 0 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -182,6 +182,12 @@ The SDK handles per-domain OIDC discovery, JWKS fetching, issuer validation, and
182
182
183
183
For more details and examples, see [examples/MultipleCustomDomains.md](examples/MultipleCustomDomains.md).
184
184
185
+
### 6. Session Expiry from the Upstream IdP
186
+
187
+
For enterprise connections, the upstream identity provider can cap how long a user's session lives. When the connection is configured to honor it, Auth0 includes a `session_expiry` claim in the ID token, and the SDK enforces this ceiling on every session read. Once it is reached, `get_user()` and `get_session()` return `None`, and `get_access_token()` raises an `AccessTokenError` with code `session_expired`. If the asserted ceiling is already in the past at login, `complete_interactive_login()` raises a `SessionExpiredError` instead of persisting an already-expired session.
188
+
189
+
For more details and examples, see [examples/RetrievingData.md](examples/RetrievingData.md#session-expiry-from-the-upstream-idp).
Read more above in [Configuring the Store](./ConfigureStore.md).
72
72
73
+
## Session Expiry from the Upstream IdP
74
+
75
+
For enterprise connections, the upstream identity provider can impose a ceiling on how long the user's session may live. This ceiling is delivered to the SDK as a `session_expiry` claim (an absolute Unix timestamp, **in seconds**) on the ID token. The SDK reads this value at login, stores it with the session, and enforces it on every subsequent read.
76
+
77
+
### Emitting the claim
78
+
79
+
The `session_expiry` claim is set by a Post-Login Action on your tenant, and **must** be an absolute Unix timestamp in **seconds**, not milliseconds. For the canonical Action setup, see the [Auth0 documentation](https://auth0.com/docs) (will be adding the link to the session_expiry Action guide once published).
80
+
81
+
> [!WARNING]
82
+
> `session_expiry` is interpreted as **seconds** since the Unix epoch (per RFC 7519 `NumericDate`). A common mistake is emitting milliseconds (e.g. `getTime()` without `/ 1000`). The SDK rejects implausibly large values (anything at or above `10_000_000_000`, ≈ year 2286) as malformed and treats them as **no ceiling**, so a milliseconds value will silently disable enforcement rather than expiring the session ~55,000 years from now. Always divide by 1000.
83
+
>
84
+
> Because the claim is authored by your Action (untrusted input), the SDK **fails open** on any malformed value — a non-numeric, zero, negative, boolean, or millisecond value is treated as "no ceiling" and login proceeds normally. Only a clean, future, seconds timestamp is enforced.
85
+
86
+
Once the ceiling is reached, the read methods behave as follows:
87
+
88
+
-`get_user()` returns `None`, as if no session exists.
89
+
-`get_session()` returns `None`, as if no session exists.
90
+
-`get_access_token()` raises an `AccessTokenError` with code `session_expired`.
91
+
92
+
`get_access_token_for_connection()` (Token Vault) is **not** gated by the session ceiling — connection tokens follow the upstream IdP's own `expires_in`, so they remain retrievable from cache even after the session ceiling has passed.
93
+
94
+
```python
95
+
from auth0_server_python.error import AccessTokenError, AccessTokenErrorCode
if error.code == AccessTokenErrorCode.SESSION_EXPIRED:
101
+
# The upstream session ceiling has been reached; start a new login.
102
+
...
103
+
```
104
+
105
+
When the ceiling is reached, the SDK deletes the stored session before returning, so the next request starts clean.
106
+
107
+
If the upstream IdP asserts a ceiling that is already in the past at login time, `complete_interactive_login()` raises a `SessionExpiredError` rather than persisting an already-expired session:
108
+
109
+
```python
110
+
from auth0_server_python.error import SessionExpiredError
# The session was already past its ceiling on arrival; start a new login.
116
+
...
117
+
```
118
+
119
+
> [!NOTE]
120
+
> **Upgrading:** with this feature enabled, `get_user()` and `get_session()` can return `None` for a user who was previously logged in, once the upstream ceiling passes. Applications that assumed these always return a value after login should add a null check and route the user back through login.
121
+
122
+
The `session_expiry` value is also surfaced through the user claims, so you can read it without triggering enforcement:
123
+
124
+
```python
125
+
user =await server_client.get_user(store_options=store_options)
126
+
session_expires_at = (user or {}).get("session_expiry")
127
+
```
128
+
129
+
> [!NOTE]
130
+
> Enforcement applies a small negative leeway (30 seconds) to account for clock skew, so a session is treated as expired slightly before the exact `session_expiry` timestamp. The refresh-token grant preserves the original ceiling - refreshing an access token does not extend the upstream session.
131
+
73
132
## Multi-Resource Refresh Tokens (MRRT)
74
133
75
134
Multi-Resource Refresh Tokens allow using a single refresh token to obtain access tokens for multiple audiences, simplifying token management in applications that interact with multiple backend services.
0 commit comments