Sitemap

Native SSO

8 min readMay 6, 2025

Introduction

This article reproduces selected sections from the document “Native SSO” on Authlete’s website, which explains the “OpenID Connect Native for Mobile Apps 1.0” specification and Authlete’s implementation. For additional information, such as sample implementation of Native SSO, please refer to the original document provided by Authlete.

Concept

OpenID Connect Native SSO for Mobile Apps 1.0 (hereafter referred to as “Native SSO”) is a standard specification that defines a mechanism for achieving single sign-on (SSO) across multiple mobile applications under the control of the same vendor. If this specification is implemented, users are not required to authenticate individually for each mobile application; instead, a single authentication suffices for all applications integrated via Native SSO.

Native SSO Concept

Specification Overview

Before diving into the details, let’s start with an overview of the specification.

The first application (hereafter referred to as “App 1”) obtains the following set of tokens using the authorization code flow. Notably, the ID token conforms to the Native SSO specification, and a new type of token called a device secret is included.

  1. access token
  2. refresh token (optional)
  3. ID token (Native SSO-compliant)
  4. device secret

App 1 stores the ID token and the device secret in shared storage that the second application (hereafter referred to as “App 2”) can access.

Next, App 2 retrieves the ID token and device secret from the shared storage and sends a token exchange request using them as parameters.

In response, a token exchange response containing a new set of tokens for App 2 is returned.

To summarize, the following diagram illustrates the overview.

Native SSO Specification Overview

Device Secret

The device secret is described in the Native SSO specification as follows:

The device secret contains relevant data to the device and the current users authenticated with the device. The device secret is completely opaque to the client and as such the AS MUST adequately protect the value such as using a JWE if the AS is not maintaining state on the backend.

When issuing a device secret, the OpenID Provider obtains some form of information about the device and associates it with the device secret. Then, upon receiving a token exchange request, it verifies whether the device associated with the device secret in the request matches the device from which the request was sent.

Specification Details

App 1 Authorization Request

App 1 sends an authorization request based on the authorization code flow to the OpenID Provider via a web browser. A Native SSO-specific requirement is that the scope parameter must include both the openid scope and the device_sso scope. The device_sso scope is defined by the Native SSO specification.

The minimum required request parameters for an authorization request compliant with Native SSO are as follows:

  • client_id— The client identifier, such as app_1.
  • response_type— A space-separated list of the tokens being requested. When requesting an authorization code, it includes code.
  • scope— A space-separated list of the scopes being requested. To comply with the Native SSO specification, both openid and device_sso must be included.
  • redirect_uri— The redirect URI. According to the OpenID Connect specification, the redirect_uri parameter is required when requesting the openid scope.

Here is an example of an authorization request:

https://trial.authlete.net/api/authorization?client_id=app_1&response_type=code&scope=openid+device_sso&redirect_uri=https://nextdev-api.authlete.net/api/mock/redirection

This example actually works. When the authorization page is displayed, please enter inga and inga as the login ID and password, respectively. If you are already logged in and would like to display the login ID field and password field again, add &prompt=login at the end of the authorization request.

App 1 Token Request

A token request is constructed using the authorization code obtained from the above authorization request. The request parameters required are as follows:

  • grant_type— This is the grant type. It is a mandatory parameter regardless of the flow used. For the authorization code flow, the value should be specified as authorization_code.
  • code— This is a mandatory parameter in the authorization code flow. It specifies the authorization code obtained from the authorization request.
  • redirect_uri— This is the redirect URI. If the redirect_uri parameter was included in the preceding authorization request, it is also required in the token request. Its value must be the same as the one specified in the authorization request.

In addition to the above, depending on the application’s client type (RFC 6749 Section 2.1), whether it is confidential or public, and which client authentication method is used in the case of a confidential client, additional parameters may be required.

For example, if the client type is public, the client_id request parameter is mandatory. On the other hand, if the client type is confidential and the private_key_jwt client authentication method is used, the client_assertion and client_assertion_type request parameters are required. For more details on client authentication methods, refer to “OAuth 2.0 Client Authentication”.

The following is an example of a token request by a public client:

POST https://trial.authlete.net/api/token HTTP/1.1
Content-Type: application/x-www-form-urlencoded

client_id=app_1&grant_type=authorization_code&code={{authorization_code}}&redirect_uri=https://nextdev-api.authlete.net/api/mock/redirection

If you try this example in practice, replace {{authorization_code}} with the actual value (the authorization code obtained as a result of the authorization request).

App 1 Token Response

The token response that conforms to Native SSO includes, in addition to the access token and refresh token (optional), an ID token and a device secret that comply with Native SSO. The device secret is returned as the value of the device_secret property.

{
"access_token": "R28TIqhCydVvH2x2a3XsOzJykFEs7yFotO4ip-a2MbY",
"token_type": "Bearer",
"expires_in": 86400,
"scope": "openid device_sso",
"refresh_token": "lmlNXafSApRDAq7gZvy40ojya9bplgFSHczms46mTms",
"id_token": "eyJraWQiOiJaWUdJT0hZdUE5SXBVaWpWd1FOdWwzbkU1MzZ4MUpTV0hpT2ZkUzdzYWRnIiwiYWxnIjoiRVMyNTYifQ.eyJpc3MiOiJodHRwczovL3RyaWFsLmF1dGhsZXRlLm5ldCIsInN1YiI6IjEwMDQiLCJhdWQiOlsiYXBwXzEiXSwiZXhwIjoxNzQ2NDM3MTE5LCJpYXQiOjE3NDYzNTA3MTksImF1dGhfdGltZSI6MTc0NjM1MDY3MiwiZHNfaGFzaCI6IlhrYmdHQ1JKUTFOQUhuS25NbjhKMFhIS25fOEVNenhCOWFRdUZITk0ycDQiLCJzaWQiOiJub2RlMDM4Y2F0N2ozMDhzZzE4MjhtMXNnMmRleGwzIn0.JAYlCEbGhjJwpgSZ4lUNaXkWD2ICeDs6FCBd3bKRvKPhrrGZKUAZDRij_Bmn_AF7DyTQS5ALHl82cJqjaLCcIw",
"device_secret": "b81d5ae9-9f85-4c6d-8658-1a36ffa42c83"
}

The value of the id_token property included in the token response is the ID token:

eyJraWQiOiJaWUdJT0hZdUE5SXBVaWpWd1FOdWwzbkU1MzZ4MUpTV0hpT2ZkUzdzYWRnIiwiYWxnIjoiRVMyNTYifQ.eyJpc3MiOiJodHRwczovL3RyaWFsLmF1dGhsZXRlLm5ldCIsInN1YiI6IjEwMDQiLCJhdWQiOlsiYXBwXzEiXSwiZXhwIjoxNzQ2NDM3MTE5LCJpYXQiOjE3NDYzNTA3MTksImF1dGhfdGltZSI6MTc0NjM1MDY3MiwiZHNfaGFzaCI6IlhrYmdHQ1JKUTFOQUhuS25NbjhKMFhIS25fOEVNenhCOWFRdUZITk0ycDQiLCJzaWQiOiJub2RlMDM4Y2F0N2ozMDhzZzE4MjhtMXNnMmRleGwzIn0.JAYlCEbGhjJwpgSZ4lUNaXkWD2ICeDs6FCBd3bKRvKPhrrGZKUAZDRij_Bmn_AF7DyTQS5ALHl82cJqjaLCcIw

The payload of this ID token, when decoded using base64url, is as follows. The ID token compliant with Native SSO specification includes the ds_hash claim and the sid claim.

{
"iss": "https://trial.authlete.net",
"sub": "1004",
"aud": [
"app_1"
],
"exp": 1746437119,
"iat": 1746350719,
"auth_time": 1746350672,
"ds_hash": "XkbgGCRJQ1NAHnKnMn8J0XHKn_8EMzxB9aQuFHNM2p4",
"sid": "node038cat7j308sg1828m1sg2dexl3"
}

The ds_hash claim is the hash value of the device secret. How this hash value is calculated depends on the implementation, but the ds_hash claim allows the ID token to be associated with the device secret.

The sid claim is a string that uniquely identifies the user’s authentication session, essentially the session ID.

App 1 stores the obtained ID token and device secret in a location accessible to other applications that are integrated with Native SSO.

App 2 Token Request

The Native SSO specification extends the RFC 8693: OAuth 2.0 Token Exchange specification by adding requirements to achieve Native SSO. App 2 retrieves the ID token and device secret stored by App 1 and uses them to construct a token exchange request that complies with the Native SSO specification.

The request parameters for a token exchange request compliant with the Native SSO specification are as follows:

  • grant_type— The grant type. In a token exchange request, specify urn:ietf:params:oauth:grant-type:token-exchange.
  • audience— The intended recipient of the token issued by the token exchange request. In a Native SSO token exchange request, specify the identifier of the OpenID Provider.
  • subject_token— The token that indicates on whose behalf the token exchange is being performed. In a Native SSO token exchange request, this is the ID token.
  • subject_token_type— The identifier indicating the type of the subject_token. In a Native SSO token exchange request, the subject_token is always an ID token, so the value must be urn:ietf:params:oauth:token-type:id_token.
  • actor_token— The token that represents the actor executing the token exchange. In a Native SSO token exchange request, this is the device secret.
  • actor_token_type— The identifier indicating the type of the actor_token. In a Native SSO token exchange request, the actor_token is always a device secret, so the value must be urn:openid:params:token-type:device-secret. This is a token type newly defined by the Native SSO specification.
  • scope— The scopes to associate with the access token issued as a result of the token exchange request. This parameter is optional.

In addition to the above, depending on the application’s client type (RFC 6749 Section 2.1), whether it is confidential or public, and which client authentication method is used in the case of a confidential client, additional parameters may be required.

For example, if the client type is public, the client_id request parameter is mandatory. On the other hand, if the client type is confidential and the private_key_jwt client authentication method is used, the client_assertion and client_assertion_type request parameters are required. For more details on client authentication methods, refer to “OAuth 2.0 Client Authentication”.

The following is an example of a token exchange request by a public client:

POST https://trial.authlete.net/api/token HTTP/1.1
Content-Type: application/x-www-form-urlencoded

client_id=app_2&grant_type=urn:ietf:params:oauth:grant-type:token-exchange&audience=https://trial.authlete.net&subject_token={{id_token}}&subject_token_type=urn:ietf:params:oauth:token-type:id_token&actor_token={{device_secret}}&actor_token_type=urn:openid:params:token-type:device-secret&scope=openid

If you want to try this example in practice, replace {{id_token}} and {{device_secret}} with actual values.

App 2 Token Response

The response to the token exchange request is almost identical to the token response of the authorization code flow. The only difference is that it includes the issued_token_type property. In the case of Native SSO, the value of issued_token_type is urn:ietf:params:oauth:token-type:access_token.

{
"access_token": "rH9115-g83z9zIiCJ1mzIe8mza3bX4NaBTWmGs5qqow",
"token_type": "Bearer",
"expires_in": 86400,
"scope": "openid",
"refresh_token": "_F7NMCU1ny8DQ-3Pru_owgII52gIew0T6wuWKeIrfL4",
"id_token": "eyJraWQiOiJaWUdJT0hZdUE5SXBVaWpWd1FOdWwzbkU1MzZ4MUpTV0hpT2ZkUzdzYWRnIiwiYWxnIjoiRVMyNTYifQ.eyJpc3MiOiJodHRwczovL3RyaWFsLmF1dGhsZXRlLm5ldCIsInN1YiI6IjEwMDQiLCJhdWQiOlsiYXBwXzIiXSwiZXhwIjoxNzQ2NDM4MzUxLCJpYXQiOjE3NDYzNTE5NTEsImRzX2hhc2giOiJYa2JnR0NSSlExTkFIbktuTW44SjBYSEtuXzhFTXp4QjlhUXVGSE5NMnA0Iiwic2lkIjoibm9kZTAzOGNhdDdqMzA4c2cxODI4bTFzZzJkZXhsMyJ9.8jNNF5mpeHnbqp1FTK_1adR8FlgPmHK9_rwUzaz-o5P7RMyaelBaSj74IhxHY6wbCJeD0n_N14h8vD8zWYh-8w",
"device_secret": "b81d5ae9-9f85-4c6d-8658-1a36ffa42c83",
"issued_token_type": "urn:ietf:params:oauth:token-type:access_token"
}

Extracting the ID token from the above response example:

eyJraWQiOiJaWUdJT0hZdUE5SXBVaWpWd1FOdWwzbkU1MzZ4MUpTV0hpT2ZkUzdzYWRnIiwiYWxnIjoiRVMyNTYifQ.eyJpc3MiOiJodHRwczovL3RyaWFsLmF1dGhsZXRlLm5ldCIsInN1YiI6IjEwMDQiLCJhdWQiOlsiYXBwXzIiXSwiZXhwIjoxNzQ2NDM4MzUxLCJpYXQiOjE3NDYzNTE5NTEsImRzX2hhc2giOiJYa2JnR0NSSlExTkFIbktuTW44SjBYSEtuXzhFTXp4QjlhUXVGSE5NMnA0Iiwic2lkIjoibm9kZTAzOGNhdDdqMzA4c2cxODI4bTFzZzJkZXhsMyJ9.8jNNF5mpeHnbqp1FTK_1adR8FlgPmHK9_rwUzaz-o5P7RMyaelBaSj74IhxHY6wbCJeD0n_N14h8vD8zWYh-8w

and decoding its payload part using base64url will show this result:

{
"iss": "https://trial.authlete.net",
"sub": "1004",
"aud": [
"app_2"
],
"exp": 1746438351,
"iat": 1746351951,
"ds_hash": "XkbgGCRJQ1NAHnKnMn8J0XHKn_8EMzxB9aQuFHNM2p4",
"sid": "node038cat7j308sg1828m1sg2dexl3"
}

The values of the ds_hash and sid claims are the same as those in the ID token received by App 1, but the value of the aud claim is different. In this ID token, the identifier of App 2, app_2, is included in the aud array.

References

--

--

Takahiko Kawasaki
Takahiko Kawasaki

Written by Takahiko Kawasaki

Co-founder and representative director of Authlete, Inc., working as a software engineer since 1997. https://www.authlete.com/

No responses yet