diff --git a/main/config/navigation/authenticate.json b/main/config/navigation/authenticate.json
index f5baa710fe..0db8b7eba4 100644
--- a/main/config/navigation/authenticate.json
+++ b/main/config/navigation/authenticate.json
@@ -123,6 +123,15 @@
"docs/authenticate/single-sign-on/native-to-web/native-to-web-sso-best-practices"
]
},
+ {
+ "group": "Session Delegation",
+ "root": "docs/authenticate/single-sign-on/session-delegation",
+ "pages": [
+ "docs/authenticate/single-sign-on/session-delegation/configure-session-delegation",
+ "docs/authenticate/single-sign-on/session-delegation/implement-session-delegation",
+ "docs/authenticate/single-sign-on/session-delegation/session-delegation-behavior-and-monitoring"
+ ]
+ },
"docs/authenticate/single-sign-on/api-endpoints-for-single-sign-on",
"docs/authenticate/single-sign-on/okta-access-gateway"
]
diff --git a/main/docs/api/authentication/custom-token-exchange/get-token.mdx b/main/docs/api/authentication/custom-token-exchange/get-token.mdx
index ebcec2c809..8537094240 100644
--- a/main/docs/api/authentication/custom-token-exchange/get-token.mdx
+++ b/main/docs/api/authentication/custom-token-exchange/get-token.mdx
@@ -17,21 +17,18 @@ Custom Token Exchange is currently available in Early Access. By using this feat
### Remarks
- - The scopes issued to the application may differ from the scopes requested. In this case, a scope parameter will be included in the response JSON. Scopes are filtered out as explained in [API Access Policies for Applications](https://auth0.com/docs/ja-jp/get-started/apis/api-access-policies-for-applications)
- - The `subject_token_type` must correspond to an existing Custom Token Exchange Profile and an associated [Action](https://auth0.com/docs/customize/actions).
+Read [Custom Token Exchange](/docs/authenticate/custom-token-exchange) to understand Custom Token Exchange Profiles, how a profile maps to an Action, and how to enable this flow for your application.
- - For non-confidential applications that cannot keep the Client Secret safe (for example, native apps), the endpoint supports passing no Client Secret but the application itself must have the property `tokenEndpointAuthMethod` set to `none`. You can do this either from the UI (**Dashboard > Applications > Application Settings**) or using the Management API.
+ - The scopes issued to the application may differ from the scopes requested. In this case, a scope parameter will be included in the response JSON. Scopes are filtered out as explained in [API Access Policies for Applications](/docs/get-started/apis/api-access-policies-for-applications).
- - You have to [Enable Custom Token Exchange for your application](https://auth0.com//docs/authenticate/custom-token-exchange/configure-custom-token-exchange#enable-custom-token-exchange-for-your-application). To learn more, read the [Custom Token Exchange documentation](https://auth0.com/docs/authenticate/custom-token-exchange).
+ - MFA is not compatible with transactions where an actor is set via `setActor()`. In those cases, the request returns a `400` error: `MFA is not supported using actor_token with the requested token exchange profile.`
- - `actor_token` and `actor_token_type` must both be present or both absent. Providing only one returns a `400` error with code `invalid_request`.
+ - When the Action calls `setActor()`, issued access tokens and ID tokens include an `act` claim representing the [delegation chain](/docs/secure/call-apis-on-users-behalf/on-behalf-of-token-exchange#the-act-claim). The `act` claim is also included in the `userinfo` response.
- - When `actor_token` is present, refresh tokens are not issued. The `offline_access` scope is excluded from the response.
+ - To request a Session Transfer Token instead of an access token, set `audience` to `urn:YOUR_AUTH0_TENANT_DOMAIN:session_transfer`. Calling `setActor()` is required for this request. Read [Session Delegation](/docs/authenticate/single-sign-on/session-delegation) to learn how to redeem the resulting token to establish a session on behalf of the subject user.
- - MFA is not compatible with transactions where an actor is set via `setActor()`. If MFA is required and the Custom Token Exchange Action sets an actor, the request returns a `400` error: `MFA is not supported using actor_token with the requested token exchange profile.`
-
- - When the Action calls `setActor()`, issued access tokens and ID tokens include an `act` claim representing the [delegation chain](/docs/secure/call-apis-on-users-behalf/on-behalf-of-token-exchange#the-act-claim). The `act` claim is also included in the userinfo response.
+ - To include standard claims (such as `email`) in the issued token(s), the corresponding scope (`email`) must be included in the request, even if your Action sets the claim explicitly. To learn more, read [OpenID Connect Scopes: Standard claims](/docs/get-started/apis/scopes/openid-connect-scopes#standard-claims).
## Headers
@@ -69,7 +66,7 @@ Custom Token Exchange is currently available in Early Access. By using this feat
- (Optional) The unique identifier of the target API you want to access. The default tenant audience will be used when not present, as configured in [Tenant Settings](https://auth0.com/docs/get-started/tenant-settings).
+ (Optional) The unique identifier of the target API you want to access. The default tenant audience will be used when not present, as configured in [Tenant Settings](https://auth0.com/docs/get-started/tenant-settings). To request a [Session Transfer Token](/docs/authenticate/single-sign-on/session-delegation) for delegated session establishment instead of an access token, use `urn:YOUR_AUTH0_TENANT_DOMAIN:session_transfer`.
@@ -112,7 +109,7 @@ Custom Token Exchange is currently available in Early Access. By using this feat
- The issued token type.
+ The issued token type. For a standard exchange, this is `urn:ietf:params:oauth:token-type:access_token`. When requesting a Session Transfer Token, this is `urn:auth0:params:oauth:token-type:session_transfer_token` and the token itself is returned in `access_token`.
@@ -124,3 +121,4 @@ Custom Token Exchange is currently available in Early Access. By using this feat
| Status | Description |
|--------|-------------|
| 200 | Successful response |
+| 400 | Bad request. May occur if required parameters are missing or inconsistent (for example, only one of `actor_token`/`actor_token_type` is present), or if `setActor()` was not called when requesting a Session Transfer Token. |
diff --git a/main/docs/authenticate/custom-token-exchange.mdx b/main/docs/authenticate/custom-token-exchange.mdx
index 854a5a0f9b..76f1d6a6ac 100644
--- a/main/docs/authenticate/custom-token-exchange.mdx
+++ b/main/docs/authenticate/custom-token-exchange.mdx
@@ -21,6 +21,10 @@ Custom Token Exchange enables applications to exchange their existing tokens for
To learn more, read [Example Use Cases and Code Samples](/docs/authenticate/custom-token-exchange/cte-example-use-cases).
+
+If you don't have custom token validation requirements and only need to propagate delegation context between your own services, use [On-Behalf-Of Token Exchange](/docs/secure/call-apis-on-users-behalf/on-behalf-of-token-exchange) instead. It doesn't run a custom Action per request and supports significantly higher throughput. Use Custom Token Exchange when you need to validate subject or actor tokens in a custom format, integrate an external identity provider, or otherwise need full control over the exchange logic.
+
+
Each Custom Token Exchange request maps to a [Custom Token Exchange Profile](/docs/authenticate/custom-token-exchange/configure-custom-token-exchange#create-custom-token-exchange-profile) that is governed by an [Action](/docs/customize/actions), where you can:
* Write custom code to decode and validate `subject_tokens` passed to the `/oauth/token` endpoint
diff --git a/main/docs/authenticate/custom-token-exchange/cte-example-use-cases.mdx b/main/docs/authenticate/custom-token-exchange/cte-example-use-cases.mdx
index 8a7aee8aab..26f1f555d1 100644
--- a/main/docs/authenticate/custom-token-exchange/cte-example-use-cases.mdx
+++ b/main/docs/authenticate/custom-token-exchange/cte-example-use-cases.mdx
@@ -338,7 +338,7 @@ curl --location 'https://{yourDomain}.auth0.com/oauth/token' \
Read [code samples](#code-samples) for a more detailed example on how to validate opaque refresh token with the legacy IdP.
-### Use Case: Support agent acting on behalf of an end user
+### Use Case: Support agent acting on behalf of an end user via API
GearUp's support agents need to access end-user data and perform actions via GearUp's backend APIs on behalf of the end-user. The support tool authenticates the agent, then uses the Custom Token Exchange to obtain an access token representing the end-user with the agent tracked as the actor.
@@ -426,7 +426,7 @@ The issued access token will include the `act` claim:
}
```
-### Important considerations for delegated authorization
+#### Important considerations for delegated authorization
When implementing delegated authorization with Custom Token Exchange, follow these guidelines:
@@ -442,6 +442,115 @@ When implementing delegated authorization with Custom Token Exchange, follow the
Auth0 does not notify the end-user when a delegated authorization token is issued on their behalf. If your use case requires user notification or explicit consent before delegated access takes place, consider using [Client Initiated Backchannel Authentication (CIBA)](/docs/get-started/authentication-and-authorization-flow/client-initiated-backchannel-authentication-ciba-flow) to push a consent request to the end-user's device prior to performing the token exchange. For simpler notification needs, you can implement notification logic within your Custom Token Exchange Action, a Post-Login Action, or in your downstream services.
+### Use Case: Support agent accessing a web application on behalf of an end user
+
+Sometimes a support agent needs to reproduce an issue directly in GearUp's web application, acting as the end-user, rather than just calling GearUp's API. Instead of exchanging tokens for an access token, the support tool requests a Session Transfer Token, which it uses to establish a delegated web session for the end-user in GearUp's web application.
+
+
+
+1. The support tool authenticates the agent with Auth0 and obtains the agent's ID token.
+2. The support tool calls Auth0's `/oauth/token` using a [Custom Token Exchange request](/docs/get-started/authentication-and-authorization-flow/token-exchange-flow/call-your-api-using-the-custom-token-exchange-flow), setting `audience` to `urn:YOUR_AUTH0_TENANT_DOMAIN:session_transfer`, with a signed JWT identifying the end-user as `subject_token` and the agent's ID token as `actor_token`.
+3. The associated Custom Token Exchange Action validates the subject token, authorizes the delegation, and calls `api.authentication.setActor()` and `api.authentication.setUserByConnection()` to select the connection the target application accepts. Calling `setActor()` is required when requesting a Session Transfer Token; omitting it returns a `400` error.
+4. Auth0 issues a Session Transfer Token (`issued_token_type: urn:auth0:params:oauth:token-type:session_transfer_token`) instead of an access token.
+5. The support tool redirects the agent's browser to GearUp's web application, passing the Session Transfer Token as a query parameter on GearUp's `initiate_login_uri`.
+6. GearUp's web application passes the Session Transfer Token through to its own call to Auth0's `/authorize` endpoint, which validates the token and establishes an ephemeral, time-limited session for the end-user, with the agent recorded as the actor for auditing. Read [Implement Session Delegation](/docs/authenticate/single-sign-on/session-delegation/implement-session-delegation) for the full request/response detail.
+
+
+Your web application must explicitly opt in to accept delegated sessions, and several session behaviors differ from a regular login (session lifetime, refresh tokens, MFA, and more). Read [Session Delegation](/docs/authenticate/single-sign-on/session-delegation) to configure your web application and understand these behaviors, limitations, and how to audit delegated sessions.
+
+
+The following code sample shows how to implement session delegation in the Custom Token Exchange Action. We check the requested `audience` to tell a session delegation request apart from a plain API-access request and apply a distinct authorization policy for each. Then, set the actor and the user. Auth0 decides whether to issue an access token or a Session Transfer Token based on the requested `audience`, not on the Action's logic.
+
+```javascript lines expandable
+const jwksUri = "https://gearup.com/.well-known/jwks.json";
+
+// The audience is `urn:YOUR_AUTH0_TENANT_DOMAIN:session_transfer` - a suffix check (not
+// equality) because the domain prefix varies per tenant.
+const SESSION_TRANSFER_AUDIENCE_SUFFIX = ":session_transfer";
+
+/**
+ * Handler to be executed while executing a custom token exchange request
+ * @param {Event} event - Details about the incoming token exchange request.
+ * @param {CustomTokenExchangeAPI} api - Methods and utilities to define token exchange process.
+ */
+exports.onExecuteCustomTokenExchange = async (event, api) => {
+
+ // 1. VALIDATE the end-user token received in the subject_token
+ const { isValid, payload } = await validateToken(event.transaction.subject_token);
+
+ if (!isValid) {
+ api.access.rejectInvalidSubjectToken("Invalid subject_token");
+ return;
+ }
+
+ // 2. DETECT whether this request is for a Session Transfer Token rather than
+ // an access token, so a distinct authorization policy can be applied.
+ const isSessionDelegation = event.resource_server?.identifier?.endsWith(SESSION_TRANSFER_AUDIENCE_SUFFIX);
+
+ // 3. AUTHORIZE the actor — verify the agent has the right to act on behalf of this end-user
+ const actorUser = event.transaction.actor_token_user;
+ if (!actorUser) {
+ api.access.deny("invalid_request", "Actor token is required for this profile");
+ return;
+ }
+
+ const isAuthorized = isSessionDelegation
+ ? await checkSessionDelegationPolicy(actorUser, payload.sub)
+ : await checkApiDelegationPolicy(actorUser, payload.sub);
+
+ if (!isAuthorized) {
+ api.access.deny("unauthorized_actor", "Agent is not authorized to act on behalf of this user");
+ return;
+ }
+
+ // 4. SET THE ACTOR — Auth0 issues a Session Transfer Token instead of an
+ // access token because the requested audience is the session_transfer audience.
+ api.authentication.setActor({
+ sub: actorUser.user_id,
+ sub_profile: "human",
+ role: "support"
+ });
+
+ // 5. SET THE USER by connection — the Session Transfer Token is scoped to
+ // this specific connection, so the target application can only redeem it if
+ // this connection is enabled for it. We trust the calling application to
+ // embed the intended connection as a custom claim in subject_token (it
+ // signed that token).
+ if (!payload.connection) {
+ api.access.deny("invalid_request", "subject_token missing connection claim");
+ return;
+ }
+ api.authentication.setUserByConnection(payload.connection, { user_id: payload.sub }, {
+ creationBehavior: "none",
+ updateBehavior: "none"
+ });
+
+ async function validateToken(subjectToken) {
+ // Add your code here. REFER TO CODE SAMPLES FOR DETAILED EXAMPLES
+ }
+
+ async function checkApiDelegationPolicy(agent, userId) {
+ // Implement your API-access delegation policy check here.
+ }
+
+ async function checkSessionDelegationPolicy(agent, userId) {
+ // Implement your session delegation policy check here.
+ }
+};
+```
+
+#### Important considerations for session delegation
+
+In addition to the [considerations for delegated authorization](#important-considerations-for-delegated-authorization), keep in mind:
+
+* Detect it is a session delegation request based on the `session_transfer` audience and apply specific authorization policy for that case.
+* Target application reachability depends on the specific connection your Action sets.
+* To set the connection, the application calling Custom Token Exchange needs access to the same connections as your target application(s).
+* Use separate Auth0 domains for the initiating and target applications to avoid an existing session on a shared domain blocking the delegated one.
+* Agents must log out between delegated sessions for different users.
+
+Read [Implement Session Delegation](/docs/authenticate/single-sign-on/session-delegation/implement-session-delegation) for the full end-to-end implementation detail, including these considerations.
+
## Code samples
The following code samples show best practices for common scenarios for validating incoming subject tokens in a secure and performant way.
diff --git a/main/docs/authenticate/single-sign-on/native-to-web.mdx b/main/docs/authenticate/single-sign-on/native-to-web.mdx
index 492827032d..754931e2f0 100644
--- a/main/docs/authenticate/single-sign-on/native-to-web.mdx
+++ b/main/docs/authenticate/single-sign-on/native-to-web.mdx
@@ -10,6 +10,10 @@ If your web application relies on embedded WebViews or external browsers to deli
By binding Session Transfer Tokens to the specific device through IP address or ASN, session continuity and security is maintained and ensures the authentication context remains secure throughout the transition.
+
+If you want a support agent or other authorized actor to establish a session **as another user** rather than move a user's own session from native to web, read [Session Delegation](/docs/authenticate/single-sign-on/session-delegation) instead.
+
+
## How it works

diff --git a/main/docs/authenticate/single-sign-on/native-to-web/native-to-web-sso-and-sessions.mdx b/main/docs/authenticate/single-sign-on/native-to-web/native-to-web-sso-and-sessions.mdx
index 52bf05537f..2c5153e8e2 100644
--- a/main/docs/authenticate/single-sign-on/native-to-web/native-to-web-sso-and-sessions.mdx
+++ b/main/docs/authenticate/single-sign-on/native-to-web/native-to-web-sso-and-sessions.mdx
@@ -19,6 +19,10 @@ Native to Web SSO does not change standard Auth0 [Single Sign-On](/docs/authenti
3. The user is prompted to login when a pre-existing Auth0 session is found and the `session_transfer_token` belongs to a different user. Additionally, the pre-existing Auth0 session is revoked.
4. The user is prompted to log in when a pre-existing Auth0 session is found and the `session_transfer_token` is invalid.
+
+These behaviors apply to standard Native to Web SSO. A `session_transfer_token` carrying an actor (issued for [Session Delegation](/docs/authenticate/single-sign-on/session-delegation)) behaves differently: if the subject user already has an active session, the attempt is blocked with an error page instead of revoking the existing session. Read [Delegated Session Behavior and Monitoring](/docs/authenticate/single-sign-on/session-delegation/session-delegation-behavior-and-monitoring#session-behavior) for details.
+
+
## Sessions and refresh token revocation
A [`session_transfer_token`](/docs/authenticate/single-sign-on/native-to-web/configure-implement-native-to-web#create-and-manage-session-transfer-tokens) is used to initiate a secure session in a WebView or browser to securely authenticate the user without being prompted to login. These web sessions may also issue their own refresh tokens.
diff --git a/main/docs/authenticate/single-sign-on/session-delegation.mdx b/main/docs/authenticate/single-sign-on/session-delegation.mdx
new file mode 100644
index 0000000000..16a17afff3
--- /dev/null
+++ b/main/docs/authenticate/single-sign-on/session-delegation.mdx
@@ -0,0 +1,74 @@
+---
+title: Session Delegation
+description: Understand how Session Delegation lets an authorized actor establish an audited web session on behalf of another user.
+---
+import { ReleaseStageNotice } from "/snippets/ReleaseStageNotice.jsx"
+
+
+
+Session Delegation lets an authorized actor, for example a support agent, establish a web session as another user in your application. It builds on [Custom Token Exchange](/docs/authenticate/custom-token-exchange) to issue a Session Transfer Token that identifies both the subject user and the actor, and redeems that token into a session with the same mechanism used by [Native to Web SSO](/docs/authenticate/single-sign-on/native-to-web). The delegation itself is recorded and auditable in tenant logs.
+
+
+Session Delegation solves a different problem than Native to Web SSO. Native to Web SSO carries an already-authenticated user's own session from your native application into your web application. Session Delegation instead lets a distinct, authorized actor establish a session **as another user**, for use cases such as support access or agent-assisted workflows. If you're looking to move a signed-in user from your native app to your web app, read [Native to Web SSO](/docs/authenticate/single-sign-on/native-to-web) instead.
+
+
+## How it works
+
+Session Delegation happens in two parts: your admin application first gets a Session Transfer Token, then redeems it to establish the delegated session in the target web application.
+
+```mermaid
+sequenceDiagram
+ participant Support Agent
+ participant Admin Tool
+ participant Auth0
+ participant Target Web App
+
+ Note over Support Agent,Auth0: Part 1 - Get a Session Transfer Token
+ Support Agent->>Admin Tool: Authenticates
+ Admin Tool->>Auth0: Authenticates the Agent
+ Auth0-->>Admin Tool: Issues id_token
+
+ Admin Tool->>Auth0: POST /oauth/token (Custom Token Exchange)
subject_token: end user
actor_token: agent's id_token
audience: session_transfer
+ activate Auth0
+ Note right of Auth0: Action authorizes the delegation,
calls setUserByConnection() and setActor()
+ Auth0-->>Admin Tool: Issues Session Transfer Token
+ deactivate Auth0
+
+ Note over Support Agent,Target Web App: Part 2 - Redeem the Session Transfer Token
+ Admin Tool-->>Support Agent: Redirects browser to Target Web App's
initiate_login_uri (session_transfer_token, organization)
+ Support Agent->>Target Web App: Follows redirect to initiate_login_uri
+ Target Web App->>Auth0: GET /authorize
(session_transfer_token, organization)
+ activate Auth0
+ Note right of Auth0: Validates the token, establishes an
ephemeral session with the actor
recorded in session.actor
+ Auth0-->>Target Web App: Access Token + ID Token
(both include the act claim)
+ deactivate Auth0
+```
+
+### Part 1: Get a Session Transfer Token
+
+1. The actor (a support agent) authenticates via an admin tool with Auth0 and obtains proof of their own identity, such as an Auth0 ID token, to use as an `actor_token`.
+2. The admin tool calls Auth0's [`/oauth/token`](/docs/api/authentication/custom-token-exchange/get-token) endpoint using a Custom Token Exchange request, setting `audience` to `urn:YOUR_AUTH0_TENANT_DOMAIN:session_transfer`.
+3. The associated [Custom Token Exchange Action](/docs/customize/actions/explore-triggers/custom-token-exchange) authorizes the delegation, sets the subject user (typically via `setUserByConnection()`), and calls `setActor()` to record the actor. Calling `setActor()` is required to obtain a Session Transfer Token.
+4. Auth0 issues a Session Transfer Token identifying the subject user, with the actor recorded for the transaction.
+
+### Part 2: Redeem the Session Transfer Token (browser redirect)
+
+How your application passes the Session Transfer Token to the target web application is up to your implementation, but a recommended approach is to attach it as a query parameter on the target application's `initiate_login_uri`:
+
+5. Your application redirects the actor's browser to the target application's `initiate_login_uri`, with the Session Transfer Token, and an `organization` parameter if the login needs to happen in the scope of an organization, attached as query parameters.
+6. This sends the browser to your Auth0 tenant's `/authorize` endpoint carrying the Session Transfer Token, which triggers seamless redemption. Auth0 validates the token and establishes an ephemeral, delegated session for the subject user, recording the actor in `session.actor` for auditing.
+7. The target application completes the login and receives an access token and ID token, both including an `act` claim that identifies the delegation.
+
+Read [Implement Session Delegation](/docs/authenticate/single-sign-on/session-delegation/implement-session-delegation) for the full request/response detail, how to build the redirect, and how to handle the resulting tokens. Learn how to [Configure Session Delegation](/docs/authenticate/single-sign-on/session-delegation/configure-session-delegation) for your application, and read [Delegated Session Behavior and Monitoring](/docs/authenticate/single-sign-on/session-delegation/session-delegation-behavior-and-monitoring) to understand session behavior and audit logging.
+
+## Limitations
+
+* Only the Authorization Code flow is supported for establishing a delegated session. SAML, WS-Federation, and the Implicit flow are not supported.
+* Only single-level actors are supported. Unlike Custom Token Exchange access tokens, which support up to five levels of nested actors, a Session Transfer Token accepts a single actor only.
+* **No refresh tokens are issued for delegated sessions.**
+* A delegated session cannot be established if MFA, consent, or an enrollment prompt would be required. The request fails with `interaction_required` instead of prompting.
diff --git a/main/docs/authenticate/single-sign-on/session-delegation/configure-session-delegation.mdx b/main/docs/authenticate/single-sign-on/session-delegation/configure-session-delegation.mdx
new file mode 100644
index 0000000000..84abe4fb26
--- /dev/null
+++ b/main/docs/authenticate/single-sign-on/session-delegation/configure-session-delegation.mdx
@@ -0,0 +1,103 @@
+---
+title: Configure Session Delegation
+description: Learn how to configure the client settings required to request and accept delegated sessions.
+---
+import {AuthCodeBlock} from "/snippets/AuthCodeBlock.jsx";
+import { ReleaseStageNotice } from "/snippets/ReleaseStageNotice.jsx"
+
+
+
+
+This page covers configuration only. Read [Implement Session Delegation](/docs/authenticate/single-sign-on/session-delegation/implement-session-delegation) for the security model and the request/response detail once both applications below are configured.
+
+
+## Configure your applications
+
+### Configure the requesting application
+
+The application that calls Custom Token Exchange to obtain a Session Transfer Token needs Custom Token Exchange enabled and the ability to create a Session Transfer Token:
+
+```json lines
+{
+ "token_exchange": {
+ "allow_any_profile_of_type": ["custom_authentication"]
+ },
+ "session_transfer": {
+ "can_create_session_transfer_token": true,
+ "enforce_cascade_revocation": true
+ }
+}
+```
+
+export const codeExample1 = `curl --request PATCH \
+ --url 'https://{yourDomain}/api/v2/clients/{yourClientId}' \
+ --header 'authorization: Bearer {yourMgmtApiAccessToken}' \
+ --header 'content-type: application/json' \
+ --data '{
+ "token_exchange": {
+ "allow_any_profile_of_type": ["custom_authentication"]
+ },
+ "session_transfer": {
+ "can_create_session_transfer_token": true,
+ "enforce_cascade_revocation": true
+ }
+}'`;
+
+
+
+Read [Create and manage Session Transfer Tokens](/docs/authenticate/single-sign-on/native-to-web/configure-implement-native-to-web#create-and-manage-session-transfer-tokens) for more information on the `can_create_session_transfer_token` setting.
+
+
+The application that calls Custom Token Exchange to request a Session Transfer Token must be a confidential client, authenticating with a Client Secret (or another confidential-client method). Unlike a standard Custom Token Exchange request, the `tokenEndpointAuthMethod: none` public-client option is not supported when requesting a Session Transfer Token.
+
+
+### Configure the target web application
+
+Your web application must explicitly opt in to accept delegated sessions, and accept the Session Transfer Token as a query parameter on `/authorize`:
+
+```json lines
+{
+ "session_transfer": {
+ "allowed_authentication_methods": ["cookie", "query"],
+ "enforce_device_binding": "ip", // also "none" or "asn"
+ "allow_refresh_token": false,
+ "enforce_online_refresh_tokens": true,
+ "delegation": {
+ "allow_delegated_access": true,
+ "enforce_device_binding": "ip" // this is the only allowed value for delegation
+ }
+ }
+}
+```
+
+export const codeExample2 = `curl --request PATCH \
+ --url 'https://{yourDomain}/api/v2/clients/{yourClientId}' \
+ --header 'authorization: Bearer {yourMgmtApiAccessToken}' \
+ --header 'content-type: application/json' \
+ --data '{
+ "session_transfer": {
+ "allowed_authentication_methods": ["cookie", "query"],
+ "enforce_device_binding": "ip",
+ "allow_refresh_token": false,
+ "enforce_online_refresh_tokens": true,
+ "delegation": {
+ "allow_delegated_access": true,
+ "enforce_device_binding": "ip"
+ }
+ }
+}'`;
+
+
+
+
+`allowed_authentication_methods` must include `query` because Session Delegation passes the Session Transfer Token as a URL query parameter; the cookie-based transfer used by Native to Web SSO doesn't apply here. `delegation.enforce_device_binding` only accepts `"ip"`, and IP-based device binding is enforced automatically for delegated sessions. This configuration is disabled by default and has no equivalent Dashboard UI toggle at this time: configure it through the Management API or your infrastructure-as-code tooling (Terraform, Deploy CLI).
+
+If a Session Transfer Token carrying an actor is presented to a client without `allow_delegated_access` enabled, Auth0 does not return an error; instead, it falls back to showing the login page and emits a warning (`w`) tenant log. Check for this if a delegated session unexpectedly falls back to a login prompt.
+
+
+Once both applications are configured, read [Implement Session Delegation](/docs/authenticate/single-sign-on/session-delegation/implement-session-delegation) to make the requests, and [Delegated Session Behavior and Monitoring](/docs/authenticate/single-sign-on/session-delegation/session-delegation-behavior-and-monitoring) to understand session behavior and audit logging.
diff --git a/main/docs/authenticate/single-sign-on/session-delegation/implement-session-delegation.mdx b/main/docs/authenticate/single-sign-on/session-delegation/implement-session-delegation.mdx
new file mode 100644
index 0000000000..b4e9b755fb
--- /dev/null
+++ b/main/docs/authenticate/single-sign-on/session-delegation/implement-session-delegation.mdx
@@ -0,0 +1,134 @@
+---
+title: Implement Session Delegation
+description: Learn the security model behind Session Delegation and the exact requests, redirects, and token handling needed to implement it end to end.
+---
+import { ReleaseStageNotice } from "/snippets/ReleaseStageNotice.jsx"
+
+
+
+After [configuring both applications](/docs/authenticate/single-sign-on/session-delegation/configure-session-delegation), implement the session delegation logic that makes the requests, redirects the browser to redeem the Session Transfer Token, and handles the resulting tokens.
+
+For a complete walkthrough of the Session Delegation flow, read the [Support agent accessing a web application on behalf of an end user](/docs/authenticate/custom-token-exchange/cte-example-use-cases#use-case-support-agent-accessing-a-web-application-on-behalf-of-an-end-user) use case.
+
+## Security model
+
+A delegated session is established through the same [Custom Token Exchange](/docs/authenticate/custom-token-exchange) Action logic you control for every other token exchange. Auth0 does not decide on your behalf who is allowed to act for whom. Your Action is responsible for authorizing the delegation before calling `setActor()`.
+
+Session Delegation implements several security guardrails, from configuration through runtime behavior:
+
+* Both applications must be explicitly configured for this: the requesting application must be a confidential client able to create a Session Transfer Token, and the target application must explicitly opt in via `allow_delegated_access`. To learn more about how to configure the requesting and target applications, read [Configure Session Delegation](/docs/authenticate/single-sign-on/session-delegation/configure-session-delegation).
+* The Session Transfer Token must be redeemed from the same IP address that was used to request it from the requesting application. To learn more, read the IP-binding note under [Redeem the Session Transfer Token](#redeem-the-session-transfer-token).
+* The actor identity is recorded on the session (`session.actor`) and is available to your [Actions](/docs/authenticate/single-sign-on/session-delegation/session-delegation-behavior-and-monitoring#actions) and in [tenant logs](/docs/authenticate/single-sign-on/session-delegation/session-delegation-behavior-and-monitoring#monitoring), as the actor object passed to `setActor()`.
+* The session is ephemeral and short-lived. To learn more, read [Session behavior](/docs/authenticate/single-sign-on/session-delegation/session-delegation-behavior-and-monitoring#session-behavior).
+* No refresh tokens are issued, no MFA/consent/enrollment prompts are allowed, and existing active sessions block delegated access to limit how far a delegated session can outlive or interact with a legitimate one.
+* Delegated sessions generate dedicated tenant log event types, distinct from regular logins, so you can audit them separately.
+
+## Get a Session Transfer Token
+
+Your application requests a Session Transfer Token the same way it requests any Custom Token Exchange access token, setting `audience` to `urn:YOUR_AUTH0_TENANT_DOMAIN:session_transfer`. Read the [Authentication API](/docs/api/authentication/custom-token-exchange/get-token) for the full parameter reference:
+
+```bash lines
+curl --request POST \
+ --url 'https://{yourDomain}/oauth/token' \
+ --header 'content-type: application/x-www-form-urlencoded' \
+ --data grant_type='urn:ietf:params:oauth:grant-type:token-exchange' \
+ --data audience='urn:YOUR_AUTH0_TENANT_DOMAIN:session_transfer' \
+ --data subject_token_type='{yourSubjectTokenType}' \
+ --data subject_token='{signedJwtIdentifyingTheEndUser}' \
+ --data actor_token_type='urn:ietf:params:oauth:token-type:id_token' \
+ --data actor_token='{theAgentsAuth0IdToken}' \
+ --data client_id='{yourClientId}' \
+ --data client_secret='{yourClientSecret}'
+```
+
+```json lines
+{
+ "access_token": "{sessionTransferToken}",
+ "issued_token_type": "urn:auth0:params:oauth:token-type:session_transfer_token",
+ "expires_in": 60
+}
+```
+
+
+A Session Transfer Token is short-lived, similar to an authorization code. Redeem it promptly after issuance rather than storing it for later use.
+
+
+Your Custom Token Exchange Action is responsible for:
+
+1. **Detecting the session delegation request** by checking whether the requested audience ends in `:session_transfer`.
+2. **Authorizing the actor for the specific target user** identified by `subject_token`. This will create a session on behalf of that user, a more sensitive operation than granting scoped API access.
+3. **Calling `setUserByConnection()` with the connection the target application accepts.** The Session Transfer Token is scoped to whichever connection your Action selects. Read [Target application reachability](#troubleshooting-a-failed-redemption) for the full detail on why this matters and how to select the right connection.
+4. **Calling `setActor()`** to record the actor. This is required. Omitting it when requesting a Session Transfer Token returns a `400` error.
+
+See the [Action code example](/docs/authenticate/custom-token-exchange/cte-example-use-cases#use-case-support-agent-accessing-a-web-application-on-behalf-of-an-end-user).
+
+## Redeem the Session Transfer Token
+
+How your application passes the Session Transfer Token to the target application is up to your implementation, but the recommended approach is to redirect the actor's browser to the target application's `initiate_login_uri` with the token attached as a query parameter:
+
+```
+https://your-target-app.example.com/initiate-login?session_transfer_token={sessionTransferToken}
+```
+
+If the login needs to happen in the scope of an [Organization](/docs/manage-users/organizations), also pass `organization` as a query parameter:
+
+```
+https://your-target-app.example.com/initiate-login?session_transfer_token={sessionTransferToken}&organization={orgId}
+```
+
+
+No interactive organization picker prompt is allowed during a delegated session, so `organization` must be passed explicitly rather than relying on a login-time prompt. The connection your Action selected via `setUserByConnection()` must also be linked to that organization, the same requirement that applies to a regular (non-delegated) organization login.
+
+
+Your target application's `initiate_login_uri` route should carry both parameters through to its own call to Auth0's `/authorize` endpoint. From there, Auth0 validates the Session Transfer Token. If valid, it establishes an ephemeral, delegated session for the subject user with the actor recorded in its context. No further interaction is needed from the user.
+
+
+The Session Transfer Token must be redeemed from the same IP address that was used to obtain it from the requesting application. If your requesting application's backend server makes the token exchange call, forward the actor's real IP via the `auth0-forwarded-for` header, as that will be the IP associated to the browser redirect to the `/authorize` endpoint.
+
+
+`event.session.actor` is available in [Post-Login Actions](/docs/customize/actions/explore-triggers/post-login) once the delegated session is established, containing the exact actor object passed to `setActor()` when the Session Transfer Token was issued.
+
+## Handle the resulting tokens
+
+The target application completes the standard Authorization Code flow and receives an ID token and an access token, both carrying an `act` claim that identifies the delegation:
+
+```json lines
+{
+ "sub": "auth0|end_user_id",
+ "act": {
+ "sub": "auth0|support_agent_id",
+ "sub_profile": "human",
+ "role": "support"
+ }
+}
+```
+
+Inspect the `act` claim to detect that a session is delegated and apply any special handling your application needs; for example, restricting sensitive operations or writing an audit trail entry:
+
+```javascript lines
+const { act } = jwt.decode(id_token);
+if (act) {
+ // act.sub identifies the actor (the support agent); sub identifies the end user
+ auditLog.record({ delegated: true, actorSub: act.sub });
+}
+```
+
+Downstream API servers should apply the same check against the `act` claim in the access token they receive, independent of what the target application itself does.
+
+## Troubleshooting a failed redemption
+
+If the Session Transfer Token doesn't redeem into a session as expected:
+
+1. **Does your Action detect this is a session delegation request before applying its authorization policy?** Check whether the requested audience ends in `:session_transfer` (`event.resource_server.identifier`). An Action that doesn't distinguish session delegation from plain API-access delegation may authorize or reject the wrong requests.
+2. **Is the subject user reachable through the connection your Action selected?** The Session Transfer Token is scoped to the connection your Action sets via `setUserByConnection()` or the user's primary connection, if using `setUserById()` instead. The target application can only redeem the token if that specific connection is enabled for it, not simply because the subject user also belongs to some other connection the target application allows.
+3. **Does the application calling Custom Token Exchange itself have access to that same connection?** This is a setting on the calling (actor's) application, separate from the target application, and easy to miss.
+4. **Does the target client have `allow_delegated_access: true`, and does `session_transfer.allowed_authentication_methods` include `query`?** If `allow_delegated_access` isn't set, Auth0 falls back to a normal login page instead of erroring. `query` is required since the token is passed as a query parameter, not a cookie. See [Configure the target web application](/docs/authenticate/single-sign-on/session-delegation/configure-session-delegation#configure-the-target-web-application).
+5. **If passing an `organization`, is it included explicitly, and is the connection your Action selected linked to that organization?** No interactive organization picker is allowed during a delegated session, so a missing or mismatched `organization` fails rather than prompting.
+6. **Does your `initiate_login_uri` route (or SDK helper) actually forward the `session_transfer_token` and `organization` query parameters through to `/authorize`?** Some SDK login helpers don't forward arbitrary query parameters by default — verify yours does.
+7. **Is there already an active Auth0 session for that browser and domain?** Any existing session — the subject user's own, or a previous delegated session for a different user — blocks a new delegated session. This is usually caused by the initiating and target applications sharing one Auth0 domain, and therefore one browser session cookie. Give the target application its own [Custom Domain](/docs/customize/custom-domains), distinct from the initiating application's domain, so each gets a separate cookie. Without a Custom Domain, an alternative is to have the support agent copy the target application's `initiate_login_uri`, with the token attached, into a separately-opened private/incognito browsing window. For the same reason, an agent must log out of a delegated session before a different one can be established for another user.
+8. **Was the token redeemed from a different IP than the one that requested it?** Device binding rejects this — see the IP-binding note above.
diff --git a/main/docs/authenticate/single-sign-on/session-delegation/session-delegation-behavior-and-monitoring.mdx b/main/docs/authenticate/single-sign-on/session-delegation/session-delegation-behavior-and-monitoring.mdx
new file mode 100644
index 0000000000..ab28add90d
--- /dev/null
+++ b/main/docs/authenticate/single-sign-on/session-delegation/session-delegation-behavior-and-monitoring.mdx
@@ -0,0 +1,53 @@
+---
+title: Delegated Session Behavior and Monitoring
+description: Understand how delegated sessions behave differently from regular sessions, their side effects, Actions support, and how to audit them in tenant logs.
+---
+import { ReleaseStageNotice } from "/snippets/ReleaseStageNotice.jsx"
+
+
+
+## Session behavior
+
+Delegated sessions differ from a regular Auth0 session in several ways:
+
+* **Authorization Code flow only.** SAML, WS-Federation, and the Implicit flow are not supported for establishing a delegated session.
+* **No refresh tokens.** The `offline_access` scope is excluded from any token issued during a delegated session.
+* **No interactive prompts.** MFA, consent, and enrollment prompts (for example, passkey or MFA factor enrollment) cannot be satisfied during a delegated session. If one would be triggered, the request fails with `interaction_required` instead of prompting the user.
+* **Existing sessions block delegated access.** If an active Auth0 session already exists for the browser, the delegated session attempt fails with an error page asking the user to log out first. This applies to *any* active session on that domain — the subject user's own session, or a previous delegated session established for a different user — not only a session belonging to the subject user. This is different from standard Native to Web SSO, which revokes the existing session and continues. To learn more, read [Native to Web SSO and Sessions](/docs/authenticate/single-sign-on/native-to-web/native-to-web-sso-and-sessions).
+
+
+
+ The actor, for example, a support agent, must log out of a delegated session before a different delegated session can be established for another user on the same domain.
+
+
+* **Ephemeral by default.** The session cookie is set to non-persistent or discarded when the browser closes.
+* **Fixed 2-hour session lifetime.** Both the absolute and idle timeouts are hard-coded to 2 hours for delegated sessions and are not currently configurable. The issued access token shares this same 2-hour expiration.
+* **Device binding.** Delegated sessions always enforce IP-based device binding. This cannot be disabled or changed to ASN, unlike the configurable device binding used by standard Native to Web SSO. Delegated sessions honor `is_token_endpoint_ip_header_trusted` and `auth0-forwarded-for` for determining the trusted IP, the same as Native to Web SSO.
+* **Single-level actor only.** A Session Transfer Token accepts only one level of actor. Nested actors, which are allowed up to five levels deep for Custom Token Exchange access tokens, are rejected for Session Transfer Tokens.
+* **Client user records are still written for delegated sessions.** If your Action sets custom claims in ID tokens, they will also appear in `/userinfo` calls from the subject user's own regular sessions.
+* **User grants are not auto-created** while `session.actor` is present, to avoid leaving behind permanent side effects of a delegated session.
+* **Last login, login count, and last login IP** are not updated.
+* **Welcome emails** are not sent.
+
+## Actions
+
+`event.session.actor` is available in [Post-Login Actions](/docs/customize/actions/explore-triggers/post-login) during a delegated session, containing the exact actor object passed to `setActor()` when the Session Transfer Token was issued.
+
+## Monitoring
+
+Delegated sessions generate their own tenant [log](/docs/deploy-monitor/logs) event types:
+
+| Event | Description |
+|-------|-------------|
+| `sdel` | Successful Delegated Login. |
+| `sdeleacft` | Successful Delegated Exchange of Authorization Code for Access Token. |
+| `fdeleacft` | Failed Delegated Exchange of Authorization Code for Access Token. |
+| `sdelsa` | Successful Delegated Silent Authentication. |
+| `fdelsa` | Failed Delegated Silent Authentication. |
+
+Each of these log entries includes the actor's `sub` in the log details for auditing. A warning (`w`) log is also emitted when a delegated session is blocked because the target client does not have `allow_delegated_access` enabled — see [Configure the target web application](/docs/authenticate/single-sign-on/session-delegation/configure-session-delegation#configure-the-target-web-application).
diff --git a/main/docs/customize/actions/explore-triggers/custom-token-exchange.mdx b/main/docs/customize/actions/explore-triggers/custom-token-exchange.mdx
index 58d27c133d..5ffa12c64b 100644
--- a/main/docs/customize/actions/explore-triggers/custom-token-exchange.mdx
+++ b/main/docs/customize/actions/explore-triggers/custom-token-exchange.mdx
@@ -37,6 +37,8 @@ When the request does include `actor_token` and `actor_token_type`, these values
The `act` claim set via `setActor()` is also available in Post-Login Actions via [`event.transaction.actor`](/docs/customize/actions/reference/post-login/post-login-event-object#event-transaction).
+Auth0 supports issuing a Session Transfer Token with the actor in its context, so a delegated web session can be established for another user. To learn more, read [Session Delegation](/docs/authenticate/single-sign-on/session-delegation).
+
## References
* [Event object](/docs/customize/actions/reference/custom-token-exchange/custom-token-exchange-event-object): Provides contextual information about the Token Exchange request, including the `subject_token`, IP address, client, and more.
diff --git a/main/docs/get-started/apis/scopes/openid-connect-scopes.mdx b/main/docs/get-started/apis/scopes/openid-connect-scopes.mdx
index 2a345ef595..eac0d70ba1 100644
--- a/main/docs/get-started/apis/scopes/openid-connect-scopes.mdx
+++ b/main/docs/get-started/apis/scopes/openid-connect-scopes.mdx
@@ -36,6 +36,10 @@ Standard claims included in the most commonly-used scopes are listed below, but
| `profile` | Returns claims that represent basic profile information, including `name`, `family_name`, `given_name`, `middle_name`, `nickname`, `picture`, and `updated_at`. |
| `email` | Returns the `email` claim, which contains the user's email address, and `email_verified`, which is a boolean indicating whether the email address was verified by the user. |
+
+Scope-based filtering applies regardless of how you add claims to the token. If the corresponding scope (for example, `email`) is not included in the request, the claim is removed from the issued token(s) even if you explicitly add it from postLogin Actions via `setCustomClaim()`. This applies to ID Tokens, the `/userinfo` response, and Access Tokens alike.
+
+
For an example showing how to request standard claims for your application, read [Sample Use Cases: Scopes and Claims](/docs/get-started/apis/scopes/sample-use-cases-scopes-and-claims).
## Learn more
diff --git a/main/docs/get-started/authentication-and-authorization-flow/token-exchange-flow.mdx b/main/docs/get-started/authentication-and-authorization-flow/token-exchange-flow.mdx
index d342aaaa20..606933e57c 100644
--- a/main/docs/get-started/authentication-and-authorization-flow/token-exchange-flow.mdx
+++ b/main/docs/get-started/authentication-and-authorization-flow/token-exchange-flow.mdx
@@ -21,6 +21,8 @@ When the Custom Token Exchange flow is triggered:
4. The rest of the standard Auth0 pipeline executes to generate an Auth0 access token and optionally an ID token and refresh token for the set user.
5. The requesting application can then use these newly issued tokens to securely call APIs on behalf of the user that was set in the Action.
+Using `audience` set to `urn:YOUR_AUTH0_TENANT_DOMAIN:session_transfer` returns a Session Transfer Token instead of an access token, which your application can redeem to establish a web session as another user. To learn more, read [Session Delegation](/docs/authenticate/single-sign-on/session-delegation).
+
## Get started
To use Custom Token Exchange, you need to [create a Custom Token Exchange Profile](/docs/authenticate/custom-token-exchange/configure-custom-token-exchange#create-custom-token-exchange-profile). The general workflow involves three main configuration steps followed by your API call:
diff --git a/main/docs/images/custom-token-exchange/Support-agent-accessing-a-web-application-on-behalf-of-an-end-user.png b/main/docs/images/custom-token-exchange/Support-agent-accessing-a-web-application-on-behalf-of-an-end-user.png
new file mode 100644
index 0000000000..d75b5ed199
Binary files /dev/null and b/main/docs/images/custom-token-exchange/Support-agent-accessing-a-web-application-on-behalf-of-an-end-user.png differ