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_typesmust includeurn:ietf:params:oauth:grant-type:token-exchange. -
The
scopemust includeweb_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_codepasswordurn:ietf:params:oauth:grant-type:jwt-bearerurn:ietf:params:oauth:grant-type:saml2-bearerurn: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. Theexp(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
BearerorDPoP. - 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:
- How to register a native client for DPoP.
- How to register a native client for mTLS.
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 HTTP400 Bad Requesterror. -
wsbEndpoint.forbiddenErrors– Meters requests rejected with an HTTP403 Forbiddenerror. -
wsbEndpoint.invalidTokenErrors– Meters requests rejected with an HTTP401 Unauthorizederror. -
wsbEndpoint.serverErrors– Meters requests rejected with an HTTP500 Internal Server Errorerror.
6. Session cookie cross-domain issues
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
-
The native app exchanges the ID token for a web session bootstrap token.
-
The native app makes an OpenID authentication request to sign-in the user, passing the web session bootstrap token in a custom
login_hint_tokenparameter. The Connect2id server validates the token and creates a new web session for it, resulting in a seamless sign-in experience. -
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
-
The native app exchanges the ID token for a web session bootstrap token.
-
The native app opens a link to the target web app, passing the token in a agreed upon parameter, for example
login_hint_token. -
The web app makes an OpenID authentication request to sign-in the user, passing the web session bootstrap token in a custom
login_hint_tokenparameter. 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:
- The ID token must be validated, as a locally issued token (signature and
isscheck). - The ID token
aud(audience) must include theclient_idvalue of the client making the token request. - 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. Theexpclaim 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). - 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. - The requested scope must be
web_session_bootstrapand it must be present in the registered client metadata.
Web session bootstrap token:
- 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=trueoption. - The token subject must be the ID token
sub(subject). - The token audience must include the Connect2id server issuer
URL and the
client_idof the web app that is going to make the OpenID authentication request. - The token scope must be
web_session_bootstrap. - The token should be short-lived (not exceed 1 minute).
- The token
dataobject may be populated with the ID tokenauth_time,acrand 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_idof 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:
- op.authz.requestParamsInAuthPrompt
must be set to include the
client_idandlogin_hint_tokenvalues.
Example:
op.authz.requestParamsInAuthPrompt=client_id,login_hint_token
To accept bootstrap tokens the authorisation session handler must act as follows:
-
On receiving an authentication prompt the handler must check if a token was passed in the
request.login_hint_tokenparameter. -
The token must be validated, with replay prevention. This is done at the Connect2id server token introspection endpoint using the
revoke=trueoption. The token must have the required audience and scope. Theclient_idof the OpenID authentication request (obtained fromrequest.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. -
Submit the token
sub(subject) in response to the authentication prompt. If ID tokenauth_time,acrand other claims were passed via the tokendatathey can be used to configure the new web session. Alternatively, the session may be given a specialacrto 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_secretand 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.