Skip to content
Connect2id

Web session bootstrap for native apps

This guide describes how a native app that has authenticated a user with an ID token can seamlessly bootstrap a web session with the Connect2id server for a WebView.

Use cases:

  • Seamlessly sign-in the native app user into one or more web apps that rely on the Connect2id server for the identity provision.

  • Create or refresh a Connect2id server web session for the native app user.

Assumes Connect2id server v19.6+.

1. Configuration

Enable the web session bootstrap endpoint and specify the name of the cookie used to store the IdP session IDs.

Example minimal configuration:

op.webSessionBootstrap.enable=true
op.webSessionBootstrap.cookie.name=sid

The cookie configuration properties are used to construct the Set-Cookie headers.

Example configuration specifying a cookie domain, so it doesn’t default to the current host name:

op.webSessionBootstrap.enable=true
op.webSessionBootstrap.cookie.name=sid
op.webSessionBootstrap.cookie.domain=.server.c2id.com

Example configuration that limits the allowed age of ID tokens used for web session bootstrap to 1 day (86400 seconds):

op.webSessionBootstrap.enable=true
op.webSessionBootstrap.cookie.name=sid
op.webSessionBootstrap.maxAgeIDToken=86400

Example configuration that instructs the Connect2id server to assign the bootstrapped web session the acr and amr values found in the ID token:

op.webSessionBootstrap.enable=true
op.webSessionBootstrap.cookie.name=sid
op.webSessionBootstrap.assumeIDTokenACR=true
op.webSessionBootstrap.assumeIDTokenAMR=true

Example configuration to give bootstrapped web sessions set acr and amr values, ignoring the ID token claims:

op.webSessionBootstrap.enable=true
op.webSessionBootstrap.cookie.name=sid
op.webSessionBootstrap.defaultACR=https://load.c2id.com/l1
op.webSessionBootstrap.defaultAMR=idt

The Connect2id server supports additional optional configuration properties for the web session bootstrap.

2. Native client registration

For a native client to bootstrap web sessions it must be registered with this metadata:

  • The grant_types must include urn:ietf:params:oauth:grant-type:token-exchange.

  • The scope must include web_session_bootstrap (or the configured value).

Example registration request for a native client:

POST /clients HTTP/1.1
Authorization: ztucZS1ZyFKgh0tUEruUtiSTXhnexmd6ztuc
Content-Type: application/json

{
  "application_type"           : "native",
  "grant_types"                : [ "authorization_code",
                                   "refresh_token",
                                   "urn:ietf:params:oauth:grant-type:token-exchange" ],
  "redirect_uris"              : [ "com.example.app:///auth" ],
  "token_endpoint_auth_method" : "none",
  "code_challenge_method"      : "S256",
  "scope"                      : "openid email profile web_session_bootstrap"
}

Check the client registration guide for other examples.

3. Flow

A native client bootstraps a web session by following these steps:

Step 1: Obtain ID token

The client obtains an ID token in the standard way, with the following difference: it includes the web_session_bootstrap value to the requested scope (or the configured value).

The client can store the ID token and then used it to bootstrap web sessions for a duration of time determined by op.webSessionBootstrap.maxAgeIDToken.

Example OpenID authentication request:

https://server.c2id.com/?
 response_type=code
 &scope=openid%20web_session_bootstrap
 &client_id=123
 &state=hulei8ahLauz
 &redirect_uri=com.example.app%3A%2F%2F%2Fauth

If the requested scope is consented, this results in an ID token that includes the special wsb (web session bootstrap) claim set to true.

Example ID token claims:

{
 "iss": "https://server.c2id.com",
 "sub": "alice",
 "aud": "123",
 "exp": 1311281970,
 "iat": 1311280970,
 "wsb": true
}

The Connect2id server supports issue of ID tokens enabled for web session bootstrap for these OAuth 2.0 grants:

  • authorization_code
  • password
  • urn:ietf:params:oauth:grant-type:jwt-bearer
  • urn:ietf:params:oauth:grant-type:saml2-bearer
  • urn:ietf:params:oauth:grant-type:token-exchange

Use of the implicit grant is not recommended due to security concerns.

Important:

ID tokens issued via the refresh_token grant cannot be used to obtain a web session bootstrap token. Since the refresh is a back-channel flow, it cannot verify user presence or include the acr (Authentication Context Class Reference) and amr (Authentication Methods References) claims. These claims are often required to ensure the bootstrapped web session inherits the authentication context from the original event.

Step 2: Exchange ID token for single-use bootstrap token

The client exchanges the ID token for a short-lived, single-use bootstrap token at the token endpoint. For this it uses a profile of the token exchange OAuth 2.0 grant (RFC 8693).

Token request parameters:

  • grant_type – Must be urn:ietf:params:oauth:grant-type:token-exchange.
  • scope – Must be web_session_bootstrap (or the configured
    value).
  • subject_token – Must be an ID token authorised to bootstrap web sessions (obtained with the same scope value). Its iat (issued-at) time must be within the configured maximum age and not precede any revocation event for the subject and client. The exp (expiration) may be in the past.
  • subject_token_type – Must be urn:ietf:params:oauth:token-type:id_token.

Example token request:

POST /token HTTP/1.1
Host: server.c2id.com
Content-Type: application/x-www-form-urlencoded

grant_type=urn%3Aietf%3Aparams%3Aoauth%3Agrant-type%3Atoken-exchange
&scope=web_session_bootstrap
&subject_token=eyJraWQiOiJDWHVwIiwiYWxnIjoiUlMyNTYifQ.eyJzdWIiOiJjbGFpcmUiLC...
&subject_token_type=urn%3Aietf%3Aparams%3Aoauth%3Atoken-type%3Aid_token
&client_id=123

Token response parameters:

  • access_token – The web session bootstrap token.
  • token_type – Can be Bearer or DPoP.
  • issued_token_type – Set to urn:ietf:params:oauth:token-type:access_token.
  • expires_in – The token validity lifetime, in seconds.
  • scope – Set to web_session_bootstrap (or the configured value).

Example token response:

HTTP/1.1 200 OK
Content-Type: application/json;charset=UTF-8
Cache-Control: no-store

{
  "access_token"      : "Ywjgiiy_8ERaV9D5DxhaBg.vWpARr3IzLLT_weUlltCPA",
  "token_type"        : "Bearer",
  "issued_token_type" : "urn:ietf:params:oauth:token-type:access_token",
  "expires_in"        : 30,
  "scope"             : "web_session_bootstrap"
}

Step 3: Bootstrap a web session

The client makes a POST request to the web session bootstrap endpoint, using the single-use bootstrap token.

POST /web-session-bootstrap/rest/v1 HTTP/1.1
Host: c2id.com
Authorization: Bearer 1zudgjwV3Oj3uEnjGDqD0Q.xkc9mOXIwHz8pOYiVvZBRw
Content-Type: application/x-www-form-urlencoded; charset=UTF-8

On success the Connect2id server returns a Set-Cookie header which the client can inject into the cookie jar of a WebView, then send the user to the desired URL (of a protected resource, or an IdP page).

Example response:

HTTP/1.1 204 No Content
Set-Cookie=sid=lxCY2Y954NRpN9NFjTf5QA.fMUJ5mx4YGM127L1fa-s6Q;Version=1;Domain=server.c2id.com;Path=/;Secure;HttpOnly;SameSite=Lax
Cache-Control=no-store, no-transform

The bootstrapped web session includes a special bootstrap JSON object in its data field, as explained here. This object can be used as decision input when a web application launched in the WebView is requesting sign-in or tokens from the Connect2id server and the consent prompt is triggered.

4. Sender-constrained flows with DPoP or mTLS

Native applications that use DPoP (RFC 9949) or mTLS (RFC 8705) to sender-constrain their access and refresh tokens automatically get the same protection for the ID and access tokens used to bootstrap web session.

Tips:

DPoP

Native clients that use DPoP and obtain an ID token issued with the web_session_bootstrap scope must again include a DPoP proof header when exchanging the ID token for a web session bootstrap token. The proof JWT must include the ath (access token hash) claim computed as the SHA-256 hash of the ID token.

Example request to exchange the ID token for a DPoP access token for the web session bootstrap endpoint:

POST /token HTTP/1.1
Host: server.c2id.com
DPoP: eyJ0eXAiOiJkcG9wK2p3dCIsImFsZyI6IkVTMjU2IiwiandrIjp7Imt0eSI6IkVDIiwieC...
Content-Type: application/x-www-form-urlencoded

grant_type=urn%3Aietf%3Aparams%3Aoauth%3Agrant-type%3Atoken-exchange
&scope=web_session_bootstrap
&subject_token=eyJraWQiOiJDWHVwIiwiYWxnIjoiUlMyNTYifQ.eyJzdWIiOiJjbGFpcmUiLC...
&subject_token_type=urn%3Aietf%3Aparams%3Aoauth%3Atoken-type%3Aid_token
&client_id=123

Similarly, the following call to bootstrap a web session includes a DPoP proof header with the ath (access token hash) claim computed as the SHA-256 hash of the access token.

The ID tokens that are DPoP-bound for this purpose include a cnf.jkt (JWK thumbprint confirmation) claim.

mTLS

Native clients that use client X.509 certificate bound tokens and obtain an ID token issued with the web_session_bootstrap scope must again include the certificate when exchanging the ID token for a web session bootstrap token, and then when bootstrapping the web session.

The ID tokens that are client certificate-bound for this purpose include a cnf.x5t#S256 (X.509 certificate SHA-256 thumbprint confirmation) claim.

5. Metrics

Use of the web session bootstrap endpoint can be monitored with these metrics:

  • wsbEndpoint.successfulRequests – Meters successful web session bootstrap endpoint requests.

  • wsbEndpoint.invalidRequestErrors – Meters requests rejected with an HTTP 400 Bad Request error.

  • wsbEndpoint.forbiddenErrors – Meters requests rejected with an HTTP 403 Forbidden error.

  • wsbEndpoint.invalidTokenErrors – Meters requests rejected with an HTTP 401 Unauthorized error.

  • wsbEndpoint.serverErrors – Meters requests rejected with an HTTP 500 Internal Server Error error.

If the web session bootstrap endpoint of the deployed Connect2id server is at a different web domain than the IdP login page (where the session cookies normally get set), a reverse proxy is going to be required, to satisfy Same-Origin policy and SameSite cookie restrictions.

Example:

  • IdP login page: https://sso.c2id.com/login
  • Connect2id server deployment: https://server.c2id.com
  • Connect2id server web session bootstrap endpoint: https://server.c2id.com/web-session-boostrap/rest/v1

Deploy a reverse proxy (e.g., Nginx, Apache) to serve both the IdP login page and the bootstrap endpoint under the same domain. This ensures cookies are shared seamlessly.

Example Nginx configuration:

server {
    listen 443 ssl;
    server_name sso.c2id.com;

    location /web-session-bootstrap/rest/v1 {
        proxy_pass https://server.c2id.com/web-session-bootstrap/rest/v1;
    }
}

7. Alternative flows

This section describes two alternative flows to bootstrap a web session at the Connect2id server, by using a custom OpenID authentication request.

Variant 1: Bootstrap via an OpenID authentication request

  1. The native app exchanges the ID token for a web session bootstrap token.

  2. The native app makes an OpenID authentication request to sign-in the user, passing the web session bootstrap token in a custom login_hint_token parameter. The Connect2id server validates the token and creates a new web session for it, resulting in a seamless sign-in experience.

  3. Subsequent OpenID authentication requests from web apps that utilise the established web session will also result in a seamless sign-in experience.

Variant 2: Bootstrap via an OpenID authentication request initiated by the web app

  1. The native app exchanges the ID token for a web session bootstrap token.

  2. The native app opens a link to the target web app, passing the token in a agreed upon parameter, for example login_hint_token.

  3. The web app makes an OpenID authentication request to sign-in the user, passing the web session bootstrap token in a custom login_hint_token parameter. The Connect2id server validates the token and creates a new web session for it, resulting in a seamless sign-in experience.

7.1. Custom ID token for web bootstrap token exchange

The alternative flows can use the provided token exchange support, or a devise their own, as described in this section.

Custom token exchange grant handling is done by a Connect2id server plugin.

Token request validation:

  1. The ID token must be validated, as a locally issued token (signature and iss check).
  2. The ID token aud (audience) must include the client_id value of the client making the token request.
  3. The ID token exp (expiration) may be in the past, as this claim is used to indicate the time after which the token must not be accepted by the OpenID relying party for the user authentication. The exp claim is not related to the user session expiration at the Connect2id server. The handler should, however, require a reasonable freshness of the ID token (see next point).
  4. The ID token iat (issued-at time) should be reasonably recent and not older than the expiration time of refresh tokens issued to the native client.
  5. The requested scope must be web_session_bootstrap and it must be present in the registered client metadata.

Web session bootstrap token:

  1. Must be issued as an identifier-based (not JWT-encoded) access token, to enforce one-time use of the token at the introspection endpoint with the revoke=true option.
  2. The token subject must be the ID token sub (subject).
  3. The token audience must include the Connect2id server issuer URL and the client_id of the web app that is going to make the OpenID authentication request.
  4. The token scope must be web_session_bootstrap.
  5. The token should be short-lived (not exceed 1 minute).
  6. The token data object may be populated with the ID token auth_time, acr and other claims to initialise the web session later.

Connect2id server deployments that choose to utilise the web-based handler (web-hook) to process requests for web session bootstrap tokens should set up the handler according to the above requirements.

Example configuration, to accept ID tokens and verify their digital signature prior to invoking the web-hook:

op.grantHandler.tokenExchange.webAPI.enable=true
op.grantHandler.tokenExchange.webAPI.url=[web-hook-url]
op.grantHandler.tokenExchange.webAPI.apiAccessToken=[web-hook-access-token]
op.grantHandler.tokenExchange.webAPI.subjectToken.types=urn:ietf:params:oauth:token-type:id_token
op.grantHandler.tokenExchange.webAPI.subjectToken.jwtVerification.1.jwkSetURI=[connect2id-server-jwk-set-url]
op.grantHandler.tokenExchange.webAPI.subjectToken.jwtVerification.mustPass=true

To allow the issue of the web session bootstrap token the handler returns a response with the following parameters:

  • sub – The user identifier from the ID token.
  • issued_token_type – Must be urn:ietf:params:oauth:token-type:access_token.
  • scope – Must be ["web_session_bootstrap"].
  • access_token.lifetime – The web session bootstrap token validity, in seconds.
  • access_token.encoding – Must be IDENTIFIER.
  • access_token.audience – Must contain the Connect2id server issuer URL and the client_id of the web app.
  • refresh_token.issue – Must be false.

To deny the issue the handler returns an error.

Example handler response:

{
  "sub"               : "164476e0-5c10-4cf0-bf75-b30fec2ba925",
  "issued_token_type" : "urn:ietf:params:oauth:token-type:access_token",
  "scope"             : [ "web_session_bootstrap" ],
  "access_token"      : { "lifetime" : 120,
                          "encoding" : "IDENTIFIER",
                          "audience" : [ "https://demo.c2id.com" ] },
  "refresh_token"     : { "issue" : false }
}

7.2. OpenID authentication with a web session bootstrap token

A client in possession of a web session bootstrap token is able to make an OpenID authentication request, skipping the login prompt.

Connect2id server configuration:

Example:

op.authz.requestParamsInAuthPrompt=client_id,login_hint_token

To accept bootstrap tokens the authorisation session handler must act as follows:

  1. On receiving an authentication prompt the handler must check if a token was passed in the request.login_hint_token parameter.

  2. The token must be validated, with replay prevention. This is done at the Connect2id server token introspection endpoint using the revoke=true option. The token must have the required audience and scope. The client_id of the OpenID authentication request (obtained from request.client_id) is used to check token audience. If the token is invalid or expired, the handler must present the regular login prompt to the end-user.

  3. Submit the token sub (subject) in response to the authentication prompt. If ID token auth_time, acr and other claims were passed via the token data they can be used to configure the new web session. Alternatively, the session may be given a special acr to clearly indicate that it was bootstrapped with a token.

8. Future directions

8.1 Use of native SSO device secrets, with optional sender constraining

Connect2id is researching an alternative flow where the native app is provisioned with a device_secret that links to a native client group session managed by the IdP. These sessions were originally devised for the OpenID Connect native SSO.

Features:

  • Ending, expiring and revoking a device session immediately removes the ability of the native app to obtain web session bootstrap tokens. This is
    further chained to automatically close any web sessions that were bootstrapped from it.
  • The device_secret and the web session bootstrap token can be sender-constrained, with DPoP or mTLS.
  • Straightforward conversion from a device to a web session.

9. Credits

The flows described here are based on the following previous work:

  • OAuth 2.0 Bootstrap to Web Session (draft 02), by George Fletcher (2013-01-07).
  • Work on Connect2id server deployments.