OpenID Connect native SSO explained
Vendors with multiple native applications in their portfolio can now offer a smooth login experience to their users, keeping the good security properties of OpenID Connect intact while benefiting from a strong, device-based session management.
1. Who is native SSO for?
If you are a vendor that offers a suite of mobile or desktop applications that require the user to be authenticated, this may be exactly what you have been looking for, so read on.
Single-app vendors are not concerned with this OpenID Connect extension for device-based single sign-on (SSO) as it relies on the sharing of an ID token and a device-bound secret between the applications participating in the SSO. This requires a level of trust between the apps that is only practical when they belong to the same vendor.
2. The benefits of native SSO
The leading benefit is the seamless login and logout experience for users, without compromises that can adversely compromise the security of the user or the vendor’s products.
Smooth SSO on the device
The user is asked to authenticate only once, into any one of the vendor’s apps enabled for SSO. At that instant the user may have installed only one of the vendor’s apps.
When the user opens another app of the vendor, which may be installed before or after the authentication, the user can be given the choice to automatically logged into it. Additional interaction (beyond a simple confirmation) or the launching of the system browser (or another app) is not required. The app then obtains the necessary tokens for its operation, such as access, ID and refresh token.
Single logout
With a single command the user is able to logout from all apps of the vendor present on the device. The logout command can be triggered in two ways:
- From any one of the vendor’s apps.
- From the user’s control panel for logins and granted authorisations at the IdP.
The logout automatically disables all refresh tokens issued to the vendor’s apps on the device.
Authentication step-up or additional consent
Privileged or sensitive operations can be made to trigger a step-up in the user authentication or request additional consent. The new authentication level (ACR) is automatically applied to the device session, which is shared by the participating apps.
Device session management
The device session for the user is represented by a secret token, called device secret, that is cryptographically secured. The session has a set lifetime and a maximum idle time. This enables the IdP to expire the session after a certain time or duration of inactivity.
The following operations, by any of the vendor’s apps, count as device session activity:
- A back-channel SSO request.
- A token refresh.
- A front-channel OpenID authentication request.
Expiration of the device session disables all refresh tokens issued to the apps. To continue, the user must log in again.
Some of the above features are not part of the native SSO specification, but additions invented for the Connect2id server and particular to its APIs.
Distinct app authorisations
The native apps in the device session maintain a distinct identity in regard to the IdP. Every app is issued with its own token(s), to the app’s client_id
, with scope and other properties that are independent from the tokens issued to the other vendor apps. The app’s tokens can thus follow their own, separate lifecycle and be managed independently.
3. Prerequisites
OpenID Connect Native SSO relies on two credentials – a device session secret and an ID token, that the vendor’s apps must store in a location accessible only to them. Other apps or users on the device must not have the means to access these credentials. If they do, there is risk of impersonation and illegitimate access to protected APIs of the app vendor.
What OS facilities are available to store the native SSO credentials?
Operating system | Recommended native SSO credential storage |
---|---|
Android | EncryptedSharedPreferences |
iOS, macOS | Keychain services API |
Windows | Credentials Management API |
Linux | GNOME Keyring, KWallet |
4. Native compared to web SSO
Native and web SSO are conceptually similar, by establishing a session after the user authentication, yet also differ significantly, in that the native variant requires a significant degree of trust between the apps.
Characteristic | Native SSO | Web SSO |
---|---|---|
Session credential | device secret | browser cookie |
Session credential storage | OS-specific API | browser cookie jar |
Session credential storage managed by | the vendor’s apps | the browser |
Application type | native | web, native |
Scope | vendor’s apps | any app |
Requires trust between the apps | yes | no |
5. The native SSO flow
A client app creates a device session
A device session is established when one of the vendor’s apps successfully completes an authorisation code flow with the IdP that includes the openid
and device_sso
values. These two values identify the request as being conformant with the OpenID Connect native SSO 1.0 specification.
-
openid
– This scope value requests an ID token for the user. -
device_sso
– This scope value requests the creation of a device session.
Example OpenID authentication request, note the presence of the device_sso
scope value:
https://c2id.com/login?
response_type=code
&scope=openid%20device_sso%20email%20profile
&client_id=123
&state=af0ifjsldkj
&redirect_uri=https%3A%2F%2Fclient.example.org%2Fcb
At the completion of the flow the client app must store the obtained ID token and device secret in a secure location accessible to the vendor’s apps only.
Example token response, the device_secret
is included for the native SSO:
HTTP/1.1 200 OK
Content-Type: application/json;charset=UTF-8
Cache-Control: no-store
Pragma: no-cache
{
"access_token" : "aiK9aehiejohNahk8ia7luh.inohshoh6bahGeL5eife7",
"token_type" : "Bearer",
"expires_in" : 600,
"scope" : "openid email profile",
"refresh_token" : "eyJraWQiOki8jioWihahpquofiePhieg0a...",
"id_token" : "eyJraWQiOiIxZTlnZGs3IiwiYWxnIjoiUl...",
"device_secret" : "WYqFXK7Q4HFnJv0hiT3Fgw.-oVkvSXgalUuMQDfEsh1lw"
}
The code flow is currently the only method specified in the native SSO extension for a client app to create a device session. The OAuth 2.0 password grant and the recent OAuth 2.0 first-party app flow effort that seeks to replace it are two other suitable methods.
Back-end token requests utilising the device session
An app that finds an ID token and a device_secret
available in its credential store shared with the vendor’s other apps, can assume the user is already signed in and thus proceed with a direct back-channel token request to the IdP.
As usual, the client app uses the scope
parameter to indicate the requested access. The openid
scope value can be included to request a new ID token for the signed in user. When the scope
parameter is omitted the convention stipulates that the scope
values registered in the client metadata apply.
The token request follows a profile of the OAuth 2.0 token exchange grant (RFC 8693) devised for the purposes of native SSO. This enables the client app to prove that it has a device_secret
and a cryptographically bound ID token for the signed-in user.
- The ID token must be passed in the
subject_token
parameter and the parameter content indicated in thesubject_token_type
. - The
device_secret
must be passed in theactor_token
parameter and the parameter content indicated in theactor_token_type
.
Example token request with scope values openid
, email
and profile
(note that the grant type is token exchange):
POST /token HTTP/1.1
Host: c2id.com
grant_type=urn%3Aietf%3Aparams%3Aoauth%3Agrant-type%3Atoken-exchange
&subject_token=eyJraWQiOiIxZTlnZGs3IiwiYWxnIjoiUl...
&subject_token_type=urn%3Aietf%3Aparams%3Aoauth%3Atoken-type%3Aid-token
&actor_token=WYqFXK7Q4HFnJv0hiT3Fgw.-oVkvSXgalUuMQDfEsh1lw
&actor_token_type=urn%3Ax-oath%3Aparams%3Aoauth%3Atoken-type%3Adevice-secret
&scope=openid%20email%20profile
If the device session is still active the client app receives the requested token(s).
Example token response with an access, ID and refresh token:
HTTP/1.1 200 OK
Content-Type: application/json;charset=UTF-8
Cache-Control: no-store
Pragma: no-cache
{
"access_token" : "eepeizaGhu8hhochu3Athe.e3cef9aiNgie9sIey2Kain",
"issued_token_type" : "urn:ietf:params:oauth:token-type:access_token",
"token_type" : "Bearer",
"expires_in" : 600,
"scope" : "openid email profile",
"refresh_token" : "eyJraWQiOki8jioWihahpquofiePhieg0a...",
"id_token" : "eyJraWQiOiIxZTlnZGs3IiwiYWxnIjoiUl..."
}
This example showed how a client app was able to skip the user authentication by relying on device session.
When making a token request that relies on a device session client apps must be prepared to handle the following error conditions:
-
Closed or expired device session – The Connect2id server indicates this with the
interaction_required
error code. If the device session is no longer active the client app must initiate a new front-channel OpenID authentication request that includes thedevice_sso
scope, in order to create a new device session. -
Step-up authentication or additional consent required – Also indicated by the
interaction_required
error code. If the token request requires a higher ACR level than the current device session, or explicit user consent is required for a particular scope value, the client app must initiate a front-channel OpenID authentication request with the samescope
values. -
Invalid request or another client error – Indicated by the error codes
invalid_request
,invalid_grant
,invalid_client
or another error for an incorrectly configured client or a protocol exception. The client code or its configuration for the IdP must be fixed.
6. Further reading
The OpenID Connect Native SSO for Mobile Apps 1.0 specification is published here. It can be considered stable for implementation and we expect it to be declared final in 2025 or 2026.
The Connect2id server introduced support for device sessions in release 16.0. These can be managed just like web sessions, giving an IdP the ability to associate an ACR level with them, set an expiration time, and include special data. Client apps can close a device session by passing the device_secret
to the token revocation endpoint.