On this page

Configure SSO for Native apps

This guide provides a high-level overview of using the Native SSO feature in Okta. It also provides a use-case example of how to configure your org to use this feature.


Learning outcomes

  • Understand the Native SSO flow.
  • Set up your native application.
  • Update the policy rule for the authorization server to allow the token exchange grant.
  • Understand the device secret and refresh token idle lifetimes.
  • Verify that the device secret is valid.
  • End a desktop session by revoking the device secret.
  • Use the /logout request to revoke the device secret.

What you need


About the Native SSO feature

Native SSO enables you to protect native OpenID Connect applications, such as desktop apps and mobile apps. It also enables you to achieve Single Sign-On (SSO) and Single Logout (SLO) between these applications.

SSO between browser-based web applications is achieved by sharing cookies. Unlike web applications, native applications can't use web cookies.

Okta offers a token-based approach to achieve SSO between native applications. See OpenID Connect & OAuth 2.0 API for more information on the OAuth 2.0 and OpenID Connect endpoints.

Before you begin

This guide assumes that you have an Okta Developer Edition organization. Don't have one? Create one for free (opens new window).

Native SSO flow

A flow diagram showing the interactions in a single sign-in flow between two native applications, a user on a browser, and Okta

  1. Native app 1 starts by redirecting the user's browser to the authorization server /authorize endpoint and requests the device_sso scope.

  2. The user is prompted to authenticate.

  3. The user enters their credentials to allow the application to access resources protected by scopes.

  4. The authorization server returns the authorization code for Native app 1.

  5. The client exchanges the authorization code for tokens.

  6. The authorization server returns the tokens (id_token, refresh_token, and access_token) and the device_secret in the response.

  7. Native app 2 makes a request for a refresh_token and access_token. The request contains the id_token and the device_secret.

    Native app 2, and any other client that participates in the Native SSO flow, can use the id_token and the device_secret obtained from the initial client that authenticated (see the following diagram). To sign in automatically, the clients can use the id_token and device_secret and exchange them for tokens by making a /token request.

    ID token and device secret use

  8. The authorization server returns a new set of refresh and access tokens specifically for Native app 2. This key part in the Native SSO flow enables a user to be automatically signed in without requiring any user action.

To use the Native SSO functionality, you need to:

  • Set up your application.
  • Configure Native SSO for your Okta org.
  • Use Authorization Code with PKCE to obtain the authorization code for client 1.
  • Exchange the code for tokens.
  • Exchange existing tokens that are obtained from client 1 for a new set of tokens for client 2.
  • Validate the device secret.
  • Revoke the device secret to end the session.

This feature is based on the OpenID Connect Native SSO for Mobile Apps (opens new window) draft specification.

Set up your application

To configure Native SSO, start by setting up your application. To walk through this use case example, you need to set up two separate native applications to represent client 1 and client 2.

  1. Go to Applications > Applications from the Admin Console, and then click Create App Integration.
  2. Select OIDC - OpenID Connect as the Sign-in method, select Native Application as the Application type, and then click Next.
  3. Enter a name for your new app integration.
  4. Click Advanced in the Grant type section, and then select Token Exchange.

    Note: If you're using Classic Engine, select Token Exchange in the Grant type section.

  5. Select Allow everyone in your organization to access in the Assignments section. For this use case, grant everyone access to the application.
  6. Click Save and on the General tab that appears, click the Copy to clipboard icon for the Client ID and save the ID somewhere.
  7. Repeat the steps for client 2.

Configure Native SSO for your Okta org

Configure Native SSO for your org by updating the policy rule for the authorization server to allow the token exchange grant. For this use case, use the "default" custom authorization server. The org authorization server isn't supported.

Note: You must have an authorization server policy and a rule set up to allow the scopes that you need. See Create access policies and Create rules for each access policy.

To update the policy rule:

  1. From the left navigation pane in the Admin Console, go to Security > API to view your authorization servers.
  2. On the Authorization Servers tab, click the pencil icon for the "default" custom authorization server.
  3. On the Scopes tab, verify that offline_access, device_sso, and openid appear in the scopes table.
  4. Select the Access Policies tab and click the pencil for the Default Policy Rule to access the Edit Rule dialog.
  5. Select Advanced in the IF Grant type is section, and then select Token Exchange.

    Note: If you're using Classic Engine, select Token Exchange in the IF Grant type is section.

  6. Click Update Rule.

Native SSO desktop session lifetime

The device secret assumes the lifetime of the first refresh token that it was minted with. The device secret has the same idle time and maximum time as the refresh token. This conforms to the authorization server policy through which the secret was minted. From there, the device secret and refresh token idle lifetimes are independent of each other.

Other refresh tokens minted using the device secret conform to the authorization server policy that generates the tokens. The original policy still governs the device secret's idle lifetime or the maximum lifetime. This includes when the device secret is used to generate a new set of tokens.

To generate a new set of tokens:

  • Use the Authorization Code with PKCE flow to obtain the authorization code for the first client.
  • Exchange the code for tokens.
  • Exchange the existing tokens from client 1 for new tokens for client 2.

In this example, you want to SSO to multiple apps that the same company creates. Each client represents one app, and you can register multiple clients for SSO. When a user signs in to one app, all the other apps that are registered are also automatically signed in.

Note: An error occurs when you perform Native SSO token exchange using an application with a low assurance policy and another application with a high assurance policy.

Use Authorization Code with PKCE to obtain the authorization code for client 1

Provide the device_sso, openid, and offline_access scopes in the first request to the /authorize endpoint using the Authorization Code with PKCE flow. All three scopes are required in the request. Use device_sso with openid and offline_access. See the Authorization Code with PKCE flow for information on the parameters passed in this request.

Example Authorization Code flow with PKCE request

  https://${yourOktaDomain}/oauth2/default/v1/authorize?client_id=${clientId}&response_type=code&scope=openid device_sso offline_access&redirect_uri=${configuredRedirectUri}&state=state-8600b31f-52d1-4dca-987c-386e3d8967e9&code_challenge_method=S256&code_challenge=qjrzSW9gMiUgpUvqgEPE4_-8swvyCtfOVvg55o5S_es

The user is prompted to provide their credentials. After the authorization server verifies those credentials, the authorization code is sent to the redirect_uri that you specified. The following is an example of the authorization code returned.

Example response

  https://${configuredRedirectUri}/?code=S_NuB0TNeDMXD_5SKZO6FuXFOi_J9XB-sHAk0Dc0txQ&state=state-8600b31f-52d1-4dca-987c-386e3d8967e9

Exchange the code for tokens

To exchange the authorization code for tokens, pass the code to your authorization server's /token endpoint along with the code_verifier that was generated. See Exchange the code for tokens for information on the parameters that are being passed in this request.

Example request

curl --request POST \
  --url https://${yourOktaDomain}/oauth2/default/v1/token \
  --header 'accept: application/json' \
  --header 'content-type: application/x-www-form-urlencoded' \
  --data-urlencode 'grant_type=authorization_code' \
  --data-urlencode 'client_id=${clientId}' \
  --data-urlencode 'redirect_uri=${configuredRedirectUri}' \
  --data-urlencode 'code=CKA9Utz2GkWlsrmnqehz' \
  --data-urlencode 'code_verifier=M25iVXpKU3puUjFaYWg3T1NDTDQtcW1ROUY5YXlwalNoc0hhakxifmZHag'

Example response

The authorization server response includes the device_secret, and the id_token, access_token, and refresh_token:

{
    "token_type": "Bearer",
    "expires_in": 3600,
    "access_token": "eyJra....3pcxrrhSAw",
    "scope": "openid device_sso offline_access",
    "refresh_token": "FOxRzDPAGtOapDzap-rNBOSWznClz3p-zypbZ157W6c",
    "id_token": "eyJraWQiOi....VQT8GGmg",
    "device_secret": "+oUXe6pnhkDOTTjR5ZGFQoZGVBrQPiDsUWIk27ioyhM="
}

Note: Store the device_secret in a secure location on the device, such as the iOS keychain. Ensure that only authorized applications have access to the device secret.

Exchange existing tokens from client 1 for new tokens for client 2

Client 2 makes a token exchange request, and the response returns the tokens applicable for client 2.

Example request

curl --request POST \
  --url https://${yourOktaDomain}/oauth2/default/v1/token \
  --header 'Accept: application/json' \
  --header 'Content-Type: application/x-www-form-urlencoded' \
  --data-urlencode 'client_id=${client 2 ID}' \
  --data-urlencode 'grant_type=urn:ietf:params:oauth:grant-type:token-exchange' \
  --data-urlencode 'actor_token=${deviceSecret}' \
  --data-urlencode 'actor_token_type=urn:x-oath:params:oauth:token-type:device-secret' \
  --data-urlencode 'subject_token=${idToken}' \
  --data-urlencode 'subject_token_type=urn:ietf:params:oauth:token-type:id_token' \
  --data-urlencode 'scope=openid offline_access' \
  --data-urlencode 'audience=${audience}'

Note the parameters that are being passed:

  • client_id: Identifies the new client (for example, client 2) and matches the Client ID of the OAuth 2.0 application that you created.
  • grant_type: Identifies the mechanism that Okta uses to authorize the creation of the tokens. Value: urn:ietf:params:oauth:grant-type:token-exchange
  • actor_token: Identifies the device_secret that was returned in response to the authorization code request.
  • actor_token_type: Identifies the type of token in the actor_token parameter.
  • subject_token: Identifies the id_token that was returned in response to the authorization code request.
  • subject_token_type: Identifies the type of token in the subject_token parameter. Value: urn:ietf:params:oauth:token-type:id_token
  • scope: The scopes that you want to be included in the access token.
  • audience: Identifies the audience of the authorization server. Locate the value for the audience parameter in the Admin Console. From the left navigation pane, select Security > API. On the Authorization Server tab, select the pencil icon for the authorization server that you need the audience value for.

If the request is successful, the response returned includes the following tokens: id_token, refresh_token, and access token.

Note: You can pass an expired ID token as part of the token exchange grant as long as the device_secret (sid) that the id_token is associated with is still valid.

Example response

{
    "token_type": "Bearer",
    "expires_in": 3600,
    "access_token": "eyJraWQiOiJZQ...VNL3SttonAlV4NYMQ",
    "scope": "openid offline_access",
    "refresh_token": "dd1LXWH5qug6tHAZDhYBOHbqg5TxxbXvwpsIR5qjZRw",
    "id_token": "eyJraWQiOiJZQ...woMh1u6jHMQTI0fA"
}

Validate the device secret

Occasionally you may want to verify that the device secret is still valid by using the /introspect endpoint.

Example introspect request

curl --request POST \
  --url https://${yourOktaDomain}/oauth2/default/v1/introspect \
  --header 'Accept: application/json' \
  --header 'Content-Type: application/x-www-form-urlencoded' \
  --data-urlencode 'client_id=${client 1 ID}' \
  --data-urlencode 'token=${deviceSecret}' \
  --data-urlencode 'token_type_hint=device_secret'

Example introspect response

{
    "active": true,
    "sid": "102oRgEWx5lRTWHilEoGfed4w",
    "token_type": "urn:x-oath:params:oauth:token-type:device-secret",
    "exp": 1628886628
}

The /introspect endpoint returns the sid that the device secret is tied to. The same value is present in the ID token. By doing this, you can correlate and identify the ID tokens that are minted with the same device secret.

Revoke the device secret to end a desktop session

Sometimes you have to end a user's desktop session. When you do that, you’re signing the user out of every registered app. To end a desktop session, you must revoke the device secret. The revoke request signs the user out of the apps that are a part of the Native SSO flow.

Example request

curl --request POST \
  --url https://${yourOktaDomain}/oauth2/default/v1/revoke \
  --header 'Accept: application/json' \
  --header 'Content-Type: application/x-www-form-urlencoded' \
  --data-urlencode 'token=${deviceSecret}' \
  --data-urlencode 'client_id=${client 1 ID}'

Example response

HTTP/1.1 200 OK

After you revoke the device secret, the corresponding access and refresh tokens are invalidated for that device. You can verify that the revoking the secret was successful by introspecting the device secret again for that client. You should receive the following response:

{
    "active": false
}

To verify that the refresh and access tokens are also automatically invalidated for other clients, repeat the /introspect request for those tokens by using the corresponding client IDs.

Request Logout

When the user signs out of an application, the application sends a /logout request to the Okta authorization server, which revokes the device secret.

curl --request GET \
  --url https://${yourOktaDomain}/oauth2/default/v1/logout?id_token_hint=${idToken}&device_secret=${deviceSecret}&post_logout_redirect_uris=${configuredPostLogoutRedirectUri}&state=2OwvFrEMTJg

The authorization server invalidates the access and refreshes tokens that are issued for the sid and device_secret. If the invalidated refresh token is used to renew tokens, the request fails.

Okta returns a response to the post_logout_redirect_uri.

  https://${configuredPostLogoutRedirectUri}/?state=2OwvFrEMTJg