> ## Documentation Index
> Fetch the complete documentation index at: https://auth0-feat-session-delegation.mintlify.site/llms.txt
> Use this file to discover all available pages before exploring further.

# Configure Session Delegation

> Learn how to configure the client settings required to request and accept delegated sessions.

export const ReleaseStageNotice = ({feature, stage, plans, contact, terms}) => {
  const stageTextMap = {
    "beta": "Beta",
    "ea": "Early Access"
  };
  const stageText = stageTextMap[stage] || "a product release stage";
  const prsLink = "/docs/troubleshoot/product-lifecycle/product-release-stages";
  const linkify = (text, url) => {
    return <a href={url} target="_blank" rel="noreferrer" class="link">{text}</a>;
  };
  const includeDetails = (plans, contact, terms) => {
    const hasDetails = terms || plans || contact;
    if (!hasDetails) return null;
    return <span data-as="p">
            {plans && <>This feature is available for {linkify(`${plans} plans`, "https://auth0.com/pricing")}. </>}
            {contact && "To participate, contact " + contact + ". "}
            {terms && <>By using this feature, you agree to the applicable Free Trial terms in Okta's {linkify("Master Subscription Agreement", "https://www.okta.com/legal")}.</>}
        </span>;
  };
  return <Warning>
            <span data-as="p">
                <strong>The {feature} feature is in {linkify(stageText, prsLink)}.</strong>
            </span>

            {includeDetails(plans, contact, terms)}
        </Warning>;
};

export const AuthCodeBlock = ({filename, icon, language, highlight, children}) => {
  const [displayText, setDisplayText] = useState(children);
  const [copyText, setCopyText] = useState(children);
  const wrapperRef = React.useRef(null);
  useEffect(() => {
    let unsubscribe = null;
    function init() {
      if (!window.autorun || !window.rootStore) {
        return;
      }
      unsubscribe = window.autorun(() => {
        let processedChildrenForDisplay = children;
        let processedChildrenForCopy = children;
        for (const [key, value] of window.rootStore.variableStore.values.entries()) {
          const escapedKey = key.replaceAll(/[.*+?^${}()|[\]\\]/g, (String.raw)`\$&`);
          let displayValue = value;
          if (key === "{yourClientSecret}" && value !== "{yourClientSecret}") {
            displayValue = value.substring(0, 3) + "*****MASKED*****";
          }
          processedChildrenForDisplay = processedChildrenForDisplay.replaceAll(new RegExp(escapedKey, "g"), displayValue);
          processedChildrenForCopy = processedChildrenForCopy.replaceAll(new RegExp(escapedKey, "g"), value);
        }
        setDisplayText(processedChildrenForDisplay);
        setCopyText(processedChildrenForCopy);
      });
    }
    if (window.rootStore) {
      init();
    } else {
      window.addEventListener("adu:storeReady", init);
    }
    return () => {
      window.removeEventListener("adu:storeReady", init);
      unsubscribe?.();
    };
  }, [children]);
  useEffect(() => {
    if (!wrapperRef.current) return;
    const originalWriteText = navigator.clipboard.writeText.bind(navigator.clipboard);
    let isOverriding = false;
    const handleClick = e => {
      const button = e.target.closest('[data-testid="copy-code-button"]');
      if (!button || !wrapperRef.current.contains(button)) return;
      isOverriding = true;
      navigator.clipboard.writeText = text => {
        if (isOverriding) {
          isOverriding = false;
          navigator.clipboard.writeText = originalWriteText;
          return originalWriteText(copyText);
        }
        return originalWriteText(text);
      };
      setTimeout(() => {
        if (isOverriding) {
          isOverriding = false;
          navigator.clipboard.writeText = originalWriteText;
        }
      }, 100);
    };
    const wrapper = wrapperRef.current;
    wrapper.addEventListener('click', handleClick, true);
    return () => {
      wrapper.removeEventListener('click', handleClick, true);
      if (navigator.clipboard.writeText !== originalWriteText) {
        navigator.clipboard.writeText = originalWriteText;
      }
    };
  }, [copyText]);
  return <div ref={wrapperRef}>
      <CodeBlock filename={filename} icon={icon} language={language} lines highlight={highlight}>
        {displayText}
      </CodeBlock>
    </div>;
};

<ReleaseStageNotice feature="Session Delegation" stage="ea" plans="B2C Professional, B2B Professional, and Enterprise" terms="true" />

<Callout icon="file-lines" color="#0EA5E9" iconType="regular">
  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.
</Callout>

## 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 theme={null}
{
  "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
  }
}'`;

<AuthCodeBlock children={codeExample1} language="bash" filename="cURL" />

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 on the `can_create_session_transfer_token` setting.

<Callout icon="file-lines" color="#0EA5E9" iconType="regular">
  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.
</Callout>

### 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 theme={null}
{
    "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"
        }
    }
}'`;

<AuthCodeBlock children={codeExample2} language="bash" filename="cURL" />

<Callout icon="file-lines" color="#0EA5E9" iconType="regular">
  `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"` — 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 — 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.
</Callout>

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.
