Skip to main content

Session Transfer (native to web)

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 lets you bridge 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, then start a normal authorization code (+ PKCE) request in the browser with the stt parameter so the web client receives codes and tokens and the browser can establish a session.

The sequence diagram below shows the integrator-facing HTTP calls; the sections that follow explain why the browser may lack a session, what not to do (tokens in URLs), how session transfer works in cidaas, and how to wire the STT + authorization flow with concrete examples.

Prerequisites

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

  • Native app — Include session_transfer in grant_types. The native client must be allowed to mint an STT with grant_type=session_transfer at the token endpoint.
  • Web app (target_client_id) — Set allowed_native_clients to include the native app’s client_id. The web client only accepts an stt for session transfer when the STT was issued for that native client.

See grant_types and allowed_native_clients on the App Settings API schemas.

Sequence diagram

The following diagram shows the integrator-facing HTTP calls. (Internal IdP steps are omitted.)

Why the browser may have no IdP session

Web applications on your cidaas instance usually expect an identity-provider session in the browser—the cookie that makes SSO work. Native apps often keep the user signed in with tokens (access, refresh) or embedded login flows that never write that cookie to the system browser you open for a full web URL.

Session transfer exists for that gap: the user is authenticated in the app, but the system browser (or the context you open for the web app) has no usable SSO session. Typical situations:

1. Opening in WebViews (embedded browser)

Sign-in runs inside an in-app WebView or embedded browser. That environment is not the same as the system browser (Safari, Chrome, etc.): cookie and storage isolation means no shared SSO cookie for tabs opened in the real browser. When you later open your company site in Safari/Chrome or hand off to an external browser, cidaas sees no session—even though the user is still “logged in” inside the app.

2. Long-lived refresh tokens vs. timeboxed browser session

Browser SSO is tied to an IdP session cookie that is timeboxed: it ends when session lifetime or inactivity timeout (and similar rules) are reached, so the user is no longer “logged in” on the web at the IdP.

Refresh tokens are a separate contract: they can stay valid much longer, so the native app can keep obtaining new access tokens and the user may never be prompted to log in again in the app—even after the browser session has already expired.

That mismatch is common: the app still has a working refresh path, but opening a web URL in the system browser hits no active SSO session. Session transfer bridges that gap so the browser can get a fresh session and the web client proper tokens without putting refresh tokens in URLs.

3. Device code flow, then opening the web

The user authenticated with device code (or similar flows where login is not a normal browser redirect to hosted pages on this device). Opening a web link in the system browser still has no prior cidaas SSO cookie on that device, so the web property does not get automatic SSO.

If the system browser already has a valid cidaas session (for example the user previously signed in via hosted pages in that browser), session transfer is not required—a normal authorization request is enough.

What not to do: pass tokens in the URL

A quick but insecure approach is to append access or refresh tokens to the query string of a web URL.

Disadvantages:

  • Security risk — Tokens can appear in browser history, referrer headers, and server logs.
  • Wrong audience — The web application may need tokens issued for its own client_id and scopes, not the native client’s tokens.
  • No IdP session — Passing a token does not create a cidaas SSO session in the browser, so other web apps on the same instance still would not see the user as logged in.
  • Poor lifecycle — The web app cannot manage refresh/renewal the way it does after a proper OAuth code flow.

Session transfer in cidaas

Session transfer uses a short-lived Session Transfer Token (STT):

  1. The native client proves an existing session (for example via access or refresh token) at the token endpoint using the session_transfer grant and specifies the target web client (target_client_id).
  2. cidaas returns an STT (returned as access_token in the token response) with a short lifetime.
  3. The system browser starts a normal OAuth authorization request for the web client_id, including the stt parameter and PKCE (code_challenge / code_challenge_method).
  4. After successful authorization, the web application exchanges the authorization code at the token endpoint for access, ID, and optionally refresh tokens. cidaas can establish SSO cookies for the browser session.

The web client configured as target_client_id must list the native client_id in allowed_native_clients (see Prerequisites), and stt requires PKCE on the authorization request.

End-to-end flow

  1. Obtain an STT (token endpoint)POST /token-srv/token with grant_type=session_transfer, subject_token, subject_token_type, and target_client_id. Authenticate the native client as your deployment requires (for example HTTP Basic, mTLS, or JWT client assertion—see the token endpoint reference). The response returns the STT identifier as access_token and a short expires_in.
  2. Authorize in the browser (authorization endpoint) — Open GET /authz-srv/authz with the web application’s client_id, standard OAuth parameters (response_type, redirect_uri, scope, state, …), stt=<STT>, and PKCE parameters.
  3. Exchange the code (token endpoint)POST /token-srv/token with grant_type=authorization_code, the code, redirect_uri, and code_verifier (when PKCE was used).

For PKCE details see PKCE. For the authorization code step see Authorization Code Flow. For OAuth fundamentals see OAuth2 Basics.

Examples: token-srv/token and authz-srv/authz

The snippets below show how session transfer uses the token endpoint to mint an STT and the authorization endpoint to consume it. Paths and parameters match the Authentication API (for example snapshot 3.102.6). Replace placeholders with your tenant base URL, client IDs, and tokens.

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

Use grant_type=session_transfer with the fields below and authenticate the native client using the method configured for your app (not necessarily parameters in this JSON body). The access_token field in the response is the STT.

You can prove the existing session with either an access token or a refresh token via subject_token and subject_token_type.

Using the native client’s access token as subject_token:

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}"
}

Using the native client’s refresh token as subject_token:

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

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

Example token response (STT): access_token is the STT value to pass as stt in the next step; expires_in is short.

{
"access_token": "{stt_value}",
"token_type": "Bearer",
"expires_in": 600
}

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

Open the system browser (or embedded browser that shares cookies with it, depending on your UX) to the authorization endpoint for the web client (client_id = target_client_id from step 1). Include stt and PKCE (code_challenge and code_challenge_method=S256). Session transfer with stt requires PKCE.

Example URL (one line; every query value must be URL-encoded 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}

The user completes login/consent if required; cidaas redirects to redirect_uri with ?code=...&state=....

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

The web application (or its backend) exchanges the authorization code at the same token endpoint, with PKCE:

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 and alternate client authentication methods are documented on Token endpoint and Authorization request.

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 STTToken endpoint
2AuthorizeGET /authz-srv/authzWeb client client_id, stt, PKCE (code_challenge, code_challenge_method), plus standard OAuth query parametersAuthorization request
3Exchange codePOST /token-srv/tokengrant_type=authorization_code with code, redirect_uri, code_verifier (PKCE)Token endpoint
Discovery (optional)GET /.well-known/openid-configurationRead authorization_endpoint, token_endpoint, and other metadata for your tenantOpenID configuration

Validate issued JWTs in your services using Validate Token.


Need Support?

Please contact us directly on our support page.