Skip to main content

Session transfer from a native app to a web service

New feature in Trivore ID version 6.5.0.

A user who is signed in to a native app (for example a mobile app) often needs to continue in a web service in a browser. Session transfer lets the user do this without signing in again:

  1. The app exchanges the user's access token for a session transfer token at the Trivore ID token endpoint, using OAuth 2.0 Token Exchange (RFC 8693).
  2. The app opens the web service in a browser and passes the token to it.
  3. The web service starts its normal OpenID Connect sign-in and adds the token to the authorization request. Trivore ID signs the user in with the token instead of asking for credentials.

The web service gets its own tokens through its normal sign-in, so the app never shares its own tokens with it. The user also gets a Trivore ID browser session, so other web services using the same Trivore ID address get single sign-on as usual.

Shared browser session

If the app signs the user in through the system browser and keeps the browser session (for example ASWebAuthenticationSession without an ephemeral session on iOS, or Custom Tabs on Android), web services opened in the same browser already get single sign-on without session transfer. Session transfer is meant for cases where that is not possible or not reliable, such as when the app uses another browser or the browser session has ended.

Configuring the clients​

The app and the web service each have their own OpenID Connect client in Trivore ID. Only an administrator can enable session transfer, in the Admin controls of the app's client (see Registering an OpenID Connect client):

  • Allow session transfer to browser allows the client to request session transfer tokens.
  • Session transfer allowed to clients selects the clients the app may transfer users to. If none are selected, transfer is allowed to any client. Select the clients explicitly whenever possible.
  • Session transfer token lifetime sets how long the tokens are valid, at most 10 minutes. If empty, the default of 120 seconds is used.

The web service's client needs no changes. It uses the normal authorization code flow.

Requesting a session transfer token​

The app sends a token exchange request to the token endpoint, authenticating as its own client in the same way as in its other token requests. A public client (such as a mobile app using PKCE) sends only its client_id.

ParameterValue
grant_typeurn:ietf:params:oauth:grant-type:token-exchange
subject_tokenThe user's access token. It must have been issued to the requesting client.
subject_token_typeurn:ietf:params:oauth:token-type:access_token
requested_token_typeurn:trivore:id:params:oauth:token-type:session_transfer_token
audienceClient ID of the web service's client. Repeat the parameter to allow several web services; the token can then be used with any one of them.
resourceOptional. Trivore ID address (base URL, such as https://{your-id-server}, or its /openid/auth URL) where the web service signs in. Repeat the parameter for several addresses. By default the token works through all addresses of the Trivore ID service.

actor_token is not supported.

curl -X POST https://{your-id-server}/openid/token \
-d grant_type=urn:ietf:params:oauth:grant-type:token-exchange \
-d client_id={app client ID} \
-d subject_token={access token} \
-d subject_token_type=urn:ietf:params:oauth:token-type:access_token \
-d requested_token_type=urn:trivore:id:params:oauth:token-type:session_transfer_token \
-d audience={web service client ID}

A successful response follows RFC 8693. The session transfer token is in access_token, but it is not an access token and cannot be used to call APIs:

{
"access_token": "eyJ0eXAiOiJzZXNzaW9uLXRyYW5zZmVyK2p3dCIs...",
"issued_token_type": "urn:trivore:id:params:oauth:token-type:session_transfer_token",
"token_type": "N_A",
"expires_in": 120
}

The token is short-lived (by default 120 seconds, see Session transfer token lifetime above), so request it right before opening the web service, not in advance. expires_in tells the lifetime of the issued token.

Errors use the standard OAuth 2.0 error response:

ErrorReason
unauthorized_clientSession transfer is not allowed for the client.
invalid_requestA required parameter is missing, or subject_token_type or requested_token_type has another value, or actor_token was given.
invalid_grantThe access token is invalid, expired or was issued to another client, or the user no longer exists.
invalid_targetAn audience client is unknown, deactivated or not allowed for the app, or a resource is not an address of this Trivore ID service.

Passing the token to the web service​

How the app passes the token to the web service is up to the app and the web service. Typically the app opens a web service URL in the browser with the token as a parameter. Keep in mind:

  • Use HTTPS only.
  • Prefer the URL fragment or a form post over a query parameter, so that the token does not end up in server or proxy logs. If you use a query parameter, make sure the web service does not log it.
  • The web service must treat the token as an opaque string. It must not validate it or accept it as a sign-in by itself: only Trivore ID validates it.

Signing in with the token​

The web service starts its normal authorization request and adds the token in the session_transfer_token parameter. It keeps using its own state, nonce and PKCE values as usual:

https://{your-id-server}/openid/auth?client_id={web service client ID}&response_type=code&scope=openid&redirect_uri={redirect URI}&state={state}&nonce={nonce}&code_challenge={challenge}&code_challenge_method=S256&session_transfer_token={token}

If the web service uses a signed request object, it can put session_transfer_token inside the request object instead. A value in the request object takes precedence over the query parameter.

Trivore ID checks that the token is valid, not expired, and issued for this client_id, and that the app is still allowed to transfer users to this client. It then signs the user in with the authentication of the original app sign-in (its time, amr and acr), without asking for credentials or multi-factor authentication again. The rest of the sign-in continues as usual and ends with a redirect back to the web service with an authorization code.

If the token cannot be used (for example it has expired), it is ignored and the sign-in continues as if it had not been given. Usually this means the user sees the normal sign-in page.

Behaviour details​

  • Confirmation: If the client's authentication settings have Skip persistent login confirmation disabled, the user is asked to confirm the sign-in to the web service, as with persistent login. Otherwise the user is redirected to the web service straight away.
  • prompt=login: The token is ignored and the user must sign in. The token is not used up.
  • prompt=none: Works when no confirmation is needed. Otherwise Trivore ID returns interaction_required.
  • max_age and acr_values: The original app sign-in must meet them. If it does not, the token is ignored.
  • Single use: The token can be used in one browser session only. In that browser session it can be used again until it expires, so a page refresh during sign-in works. It does not work in another browser, and not after the user has signed out or switched user in that browser.

Session transfer token contents​

The token is a JWT signed by Trivore ID. Clients must not rely on its contents, which may change; they are listed here for troubleshooting.

ClaimContent
typ (header)session-transfer+jwt
issTrivore ID address through which the token was issued
subUser ID
audTrivore ID authorization endpoints (.../openid/auth) where the token can be used, limited by resource
azpClient ID of the app that requested the token
target_client_idsClient IDs of the web services (from audience)
auth_time, amr, acrAuthentication details of the original app sign-in
jti, iat, expToken ID, issue time and expiry time

The web services are deliberately not in aud. This keeps OpenID Connect libraries of the web services from mistaking the token for an ID token.

Security considerations​

  • Anyone who gets a valid session transfer token can use it to sign in as the user to the listed web services until it is used or expires. Request it only when the user is about to move to the web service, and do not store it.
  • Limit the transfer to the web services the app needs with Session transfer allowed to clients and the audience parameter.
  • Sign-in events with session transfer are logged like other OpenID Connect sign-ins, and issuing a token is logged as a Session transfer token issued event.