Skip to main content
Version: Latest (4.0.6)

Session Transfer (native to web)

Native → Web STT OAuth2 PKCE recommended

Native applications (for example mobile apps) often open company-owned web applications in the system browser: centralized profiles, webshops, help portals, and similar. Those sites typically expect an active IdP session in the browser—the same kind of session that powers Single Sign-On (SSO) for pure web apps—not only a token inside the native app.

This guide describes how session transfer bridges from a native-authenticated user to a browser session and web client tokens without putting long-lived tokens in URLs.

Overview​

Session transfer is for the case where the user is authenticated in a native client but the system browser does not yet have an IdP SSO cookie. You obtain a short-lived Session Transfer Token (STT) from the token endpoint (~10 seconds), then start a normal authorization code request in the browser with the stt parameter so the web client receives codes and tokens and the browser can establish a session.

Feature availability

Session transfer requires the tenant feature tag stt. Without it, minting an STT and redeeming stt on authorize are not available.

Prerequisites​

Configure both clients in app settings (for example via Create app or Update app on PUT /apps-srv/clients):

  • Tenant — Feature tag stt enabled.
  • Native app — Include session_transfer in grant_types. That native client is the one that calls POST /token-srv/token with grant_type=session_transfer.
  • Web app (target_client_id) — List the native app’s client_id under native_to_web_sso_settings.allowed_native_clients (Trustdesk: native-to-web SSO / allowed native clients). The web client only accepts session transfer from allowlisted native clients.
Client authentication

session_transfer is a public grant type: the native client can mint an STT with client_id plus a valid subject_token. Confidential-client authentication is optional for this grant unless your deployment policy requires it.

When you need it — and when you don’t​

WebView / embedded login

Sign-in ran in an in-app WebView. Cookie isolation means the system browser has no shared SSO cookie when you later open Safari or Chrome.

Refresh token outlives SSO

The native app still refreshes access tokens, but the browser IdP session cookie has already expired. Opening a web URL hits no active SSO.

Device code, then web

Login happened via device code (or similar) without a normal hosted-pages redirect on this device. The system browser has no prior cidaas SSO cookie.

Already signed in on the web

If the system browser already has a valid cidaas session, session transfer is not required — a normal authorization request is enough.

Sequence diagram​

Integrator-facing HTTP calls only (internal IdP steps omitted):

What not to do: pass tokens in the URL​

Appending access or refresh tokens to a web URL query string is insecure and incomplete:

  • Security risk — Tokens can appear in browser history, referrer headers, and server logs.
  • Wrong audience — The web app needs tokens for its own client_id and scopes.
  • No IdP session — A query token does not create a cidaas SSO cookie for other web apps.
  • Poor lifecycle — The web app cannot refresh/renew the way it does after a proper OAuth code flow.

How session transfer works​

1
Mint STT
Native client proves the session with subject_token at POST /token-srv/token (grant_type=session_transfer) and sets target_client_id.
2
Authorize with stt
Open the system browser to GET /authz-srv/authz for the web client_id, including stt and (recommended) PKCE.
3
Exchange code
The web app exchanges the authorization code for access, ID, and optionally refresh tokens. cidaas can set SSO cookies for the browser.

The STT is returned as access_token in the mint response. It is an opaque identifier (not a JWT) with expires_in: 10. Pass that value as the stt query parameter on authorize.

Use the web client as client_id on authorize (the same client you intended as target_client_id when minting). Access control is enforced via the web app’s allowed native clients allowlist.

Security controls​

One-time useAn STT can be redeemed only once. Replay attempts are rejected.
10-second TTLMint and open the authorize URL immediately — the window is intentionally tiny.
IP bindingAuthorize must come from the same client IP as minting, or you get AUTH10085.
Client allowlistOnly native clients listed on the web app may transfer into that web app.
PKCE (recommended)Strongly recommended for public/SPA web clients. Required when the web app enforces PKCE.
IP address binding

When the STT is minted, cidaas stores the client IP of that request. The authorization request with stt must use the same IP. VPN connect/disconnect, network switches, or proxy changes between mint and authorize cause AUTH10085. Mint the STT and open the authz URL as close together as possible on the same device/network. On AUTH10085, obtain a new STT from the current IP.

Authentication context (acr, amr, auth_time)​

When minting an STT from an active native session, cidaas preserves authentication context:

  • acr — Assurance level from the native authentication is carried into the transferred session.
  • amr — Native authentication methods are retained, and the session-transfer marker "100" is appended (for example ["touchid","100"]).
  • auth_time — Original native authentication time is preserved (not reset at transfer).

That supports step-up checks (acr_values) and max_age against the real login time across native and web.

Existing browser session​

Browser cookieBehavior
Same user as STTAuthorization can complete using the existing session. The STT is still consumed.
Different userThe user is sent to login (no account-switch prompt). The STT is already consumed, so the transfer cannot be retried with the same token.

End-to-end examples​

Replace placeholders with your tenant base URL, client IDs, and tokens.

Step 1 — Issue an STT: POST /token-srv/token​

JSON and application/x-www-form-urlencoded bodies are both accepted. The access_token field in the response is the opaque STT.

POST https://{base-url}/token-srv/token
Content-Type: application/json

{
"grant_type": "session_transfer",
"client_id": "{native_client_id}",
"subject_token": "{current_access_token}",
"subject_token_type": "urn:ietf:params:oauth:token-type:access_token",
"target_client_id": "{web_client_id}"
}

Example token response (STT):

{
"access_token": "{stt_value}",
"expires_in": 10
}
Act within 10 seconds

expires_in is 10. Open the authorization URL in the system browser immediately after minting, on the same network/IP.

Step 2 — Authorize in the browser: GET /authz-srv/authz​

Open the system browser (or a browser context that shares cookies with it) for the web client. Include stt. Include PKCE (code_challenge, code_challenge_method=S256) whenever the web app requires PKCE, and for public clients in general.

Example URL (one line; URL-encode every query value in production):

GET https://{base-url}/authz-srv/authz?response_type=code&client_id={web_client_id}&redirect_uri={url_encoded_redirect_uri}&scope=openid%20profile%20email&state={opaque_csrf_token}&nonce={nonce_if_using_openid}&code_challenge={pkce_code_challenge}&code_challenge_method=S256&stt={stt_value_from_step_1}

cidaas redirects to redirect_uri with ?code=...&state=... (and may set SSO cookies).

Step 3 — Exchange the code: POST /token-srv/token​

POST https://{base-url}/token-srv/token
Content-Type: application/json

{
"grant_type": "authorization_code",
"client_id": "{web_client_id}",
"client_secret": "{web_client_secret_if_confidential}",
"code": "{authorization_code_from_redirect}",
"redirect_uri": "{same_redirect_uri_as_in_step_2}",
"code_verifier": "{pkce_code_verifier}"
}

Full parameter lists: Token endpoint and Authorization request. For PKCE see PKCE. For the code flow see Authorization Code Flow.

API reference​

StepOperationEndpointRole in session transferDocumentation
1Issue STTPOST /token-srv/tokengrant_type=session_transfer with subject_token, subject_token_type, target_client_id; response access_token is the opaque STT (expires_in: 10)Token endpoint
2AuthorizeGET /authz-srv/authzWeb client_id, stt, standard OAuth params; PKCE when the web app requires itAuthorization request
3Exchange codePOST /token-srv/tokengrant_type=authorization_code with code, redirect_uri, code_verifier (if PKCE)Token endpoint
—Discovery (optional)GET /.well-known/openid-configurationRead authorization_endpoint, token_endpoint, and other metadataOpenID configuration

Validate issued JWTs with Validate Token.


Need Support?

Please contact us directly on our support page or reach out to cidaas support at [email protected].