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
- feat: add Session Transfer Token support for CTE impersonation via session transfer [\#139](https://github.com/auth0/auth0-server-python/pull/139) ([kishore7snehil](https://github.com/kishore7snehil))
Building on token exchange, the SDK also supports:
151
+
152
+
-**[Delegation and Impersonation](examples/CustomTokenExchange.md#3-actor-tokens-delegation)** - exchange with an `actor_token` so the issued tokens record who is acting on whose behalf (the `act` claim).
153
+
-**[Impersonation via Session Transfer (STT)](examples/CustomTokenExchange.md#8-impersonation-via-session-transfer-stt)** - mint a Session Transfer Token to log an agent into a target app as a customer, via `request_session_transfer_token()` and `build_session_transfer_redirect()`.
154
+
150
155
For more details and examples, see [examples/CustomTokenExchange.md](examples/CustomTokenExchange.md).
Copy file name to clipboardExpand all lines: examples/CustomTokenExchange.md
+93Lines changed: 93 additions & 0 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -179,6 +179,99 @@ Use standard URNs when possible:
179
179
"urn:company:legacy-token"
180
180
```
181
181
182
+
## 8. Impersonation via Session Transfer (STT)
183
+
184
+
Custom Token Exchange can also mint a **Session Transfer Token (STT)** instead of an API access token. An STT lets an initiator app (for example a support console) log an agent into a target web app **as** a customer, with the agent recorded in the `act` claim - so a support engineer can reproduce a customer's exact experience without their password.
185
+
186
+
This is a two-role, two-hop flow:
187
+
188
+
-**Initiator** (the agent's app) mints the STT and redirects with it. This is where the new SDK methods live.
189
+
-**Target** (the customer's app) forwards the STT to `/authorize` on a normal interactive login, which establishes the impersonated session.
190
+
191
+
The STT is opaque, single-use, and short-lived (~60s). The SDK requests it and helps build the redirect - it never decodes or stores it.
192
+
193
+
### Initiator: request an STT and build the redirect
194
+
195
+
```python
196
+
from auth0_server_python.auth_server.server_client import ServerClient
197
+
from auth0_server_python.error import CustomTokenExchangeError
198
+
199
+
# Mint the STT. The audience (urn:{domain}:session_transfer), grant type, and the actor are
200
+
# set by the SDK - the actor is sourced from the logged-in agent's session.
201
+
result =await auth0.request_session_transfer_token(
202
+
subject_token=subject_token, # your proof of which customer to impersonate
203
+
subject_token_type="urn:acme:customer-subject",
204
+
organization=None, # optional, sent on the mint request (separate from the redirect)
return RedirectResponse(redirect_url) # your framework performs the redirect
213
+
```
214
+
215
+
`SessionTransferTokenResult` carries `session_transfer_token`, `issued_token_type` (the session-transfer URN - the field to branch on), `expires_in`, and an informational `token_type` (`N_A`). There is no `act` on this result; `act` appears later, on the target session.
216
+
217
+
> **NOTE**: An actor is mandatory - an STT is only issued when the Action set one. By default the SDK sources the actor from the logged-in agent's session ID token, refreshing it when expired. If the agent is not logged in (no usable session ID token and none can be refreshed), the call fails client-side with `ACTOR_UNAVAILABLE` before any network request.
218
+
219
+
> **NOTE**: To use your own actor token instead of the session, pass `actor_token` (and optionally `actor_token_type`, which defaults to the ID token URN). An explicit `actor_token` takes precedence and the session is not read at all. When `actor_token_type` is the ID token URN (the default), Auth0 validates the token, so it must be:
220
+
>
221
+
> - Signed with RS256 or PS256 (HS256 is rejected, it uses a shared secret).
222
+
> - Unexpired, and carrying `sub`, `iss`, `exp`, and `iat`.
223
+
> - Issued to the same client making the exchange (its `aud` must be that client's ID).
224
+
> - Belonging to a user who still exists and is not blocked.
225
+
>
226
+
> An Auth0 ID token from the agent's own session on this client satisfies all of these. A token that fails any of them is rejected by the server.
227
+
>
228
+
> ```python
229
+
> result =await auth0.request_session_transfer_token(
230
+
>subject_token=subject_token,
231
+
>subject_token_type="urn:acme:customer-subject",
232
+
>actor_token=agent_id_token, # explicit override - session is not used
On the target, the STT rides through your normal login. `start_interactive_login` forwards arbitrary authorization parameters to `/authorize`, so your login route just passes `session_transfer_token` (and`organization`, when you want the target login org-scoped) straight through:
240
+
241
+
```python
242
+
from auth0_server_python.auth_types import StartInteractiveLoginOptions
After the callback completes, read the acting party off the session user - the same way as the [Actor Tokens (Delegation)](#3-actor-tokens-delegation) section above:
print(f"Impersonated by: {act['sub']}") # drive an impersonation banner, etc.
261
+
```
262
+
263
+
> **NOTE**: Both clients need one-time configuration through the Auth0 Dashboard or Management API. The issuing (initiator) client must be allowed to create session transfer tokens. The redeeming (target) client must be allowed to accept delegated-access sessions and to receive the token as a query parameter. See the [Auth0 documentation](https://auth0.com/docs/authenticate/custom-token-exchange) for the exact client settings.
264
+
265
+
> **NOTE**: `build_session_transfer_redirect` attaches a single-use credential to `target_login_url`, so that URL must be a trusted, app-controlled value - never one derived from untrusted input (such as a user-supplied `returnTo`), which could leak the token to an attacker host.
266
+
267
+
> **NOTE**: The impersonation session is hard-capped at 2 hours and cannot mint a refresh token (`offline_access` is dropped when an actor is present). To continue past that, re-run the flow.
268
+
269
+
### STT error codes
270
+
271
+
-`ACTOR_UNAVAILABLE`: no usable actor token (client-side; raised before any network call)
272
+
-`SETACTOR_REQUIRED`: an STT was requested but the Action did not call `setActor` (server 400)
273
+
-`SESSION_TRANSFER_DISABLED`: the session-transfer feature is not enabled for the tenant/client (server 400)
-`connection`: The connection for which an access token should be retrieved, e.g. `google-oauth2` for Google.
247
-
-`loginHint`: Optional login hint to inform which connection account to use, can be useful when multiple accounts for the connection exist for the same user.
247
+
-`login_hint`: Optional login hint to inform which connection account to use, can be useful when multiple accounts for the connection exist for the same user.
248
248
249
249
The SDK will cache the token internally, and return it from the cache when not expired. When no token is found in the cache, or the token is expired, calling `get_access_token_for_connection()` will call Auth0 to retrieve a new token and update the cache.
0 commit comments