Android Integration Guide

This guide is for developers integrating ZenKey into their Android applications.

1.0 Background

ZenKey is a secure bridge between your users and the apps and services you provide. The platform is a joint undertaking of the Mobile Authentication Taskforce, a joint venture of the four major US wireless carriers.

ZenKey leverages encryption technologies in a user's mobile phone and mobile network. The platform packages multiple factors of authentication into a streamlined experience for app and website providers, taking advantage of the unique capabilities and insights of the wireless carriers. It then applies those capabilities to provide an easy and secure way to register, login, and perform other types of authorizations within apps and services. The result for Service Providers (SP) is a better user experience and a more secure link to your users.

ZenKey makes integration easy by following the OpenID Connect (OIDC) authentication protocol.

1.1 OpenID Connect

OpenID Connect (OIDC) is an authentication protocol based on the OAuth 2.0 specification. It uses JSON Web Tokens (JWTs) obtained using OAuth 2.0 flows. The ZenKey SDK uses OIDC to support developers creating experiences in web and native applications. You can read more about OIDC here.

1.2 Authorization Flow

ZenKey is simple to use – one method for users to authenticate into all of your apps and websites.

1.2.1 Authorization on a Primary Device

Users establish their mobile device as their primary device by installing the carrier specific ZenKey app on that device. After completing a simple initial setup, users are ready to use ZenKey with third-party applications. Pressing the ZenKey button in a third party app or website from their primary device starts the authentication process.

Note: This primary device is also the device users can use to authenticate requests from other devices, such as desktops and tablets. See Section 1.2.2 Authorization on Secondary Devices.

Primary Device Flow

Step 1:   The User's Service Provider's mobile app or website makes an authorization code request to the local ZenKey app.

Step 2:   The User's ZenKey app determines the appropriate wireless carrier to perform SIM and user authentication with and returns an authorization code to your Redirect URI (see section on Redirect URI).

Step 3:   Because your user has consented to share with you, your backend server may make a token request for user info or other resources.

1.2.2 Authorization on Secondary Devices

Users can also use ZenKey to authenticate on devices other than their primary device, such as a tablet. These secondary devices rely on the user to complete the authentication process.

Users pressing the ZenKey button on a secondary device will see a visual and numeric code as a part of the secondary device authorization process. This code allows the user to associate that secondary device with their primary device.

Secondary Device Flow

Step 1:   The user is taken to a website where they can select the appropriate carrier. This is known as the carrier Discovery UI website, and is where the user chooses the carrier associated with their primary device. If the user is authorizing a secondary device from an app on a tablet, the SDK will use a webview for this step.

Step 2:   The user then scans the visual code or enters the numeric code into the ZenKey app on their primary device.

Step 3:   Once the user approves the request in the ZenKey app on their primary device, the carrier Discovery UI website gets redirected to perform authorization with a login_hint_token.

Step 4:   Your backend server makes an authorization code request to the appropriate carrier, to perform SIM and user authentication, and receives the auth code back at your Redirect URI.

Step 5:   Because you user has consented to share with you, your backend server may make a token request for user info or other resources.

1.3 User Data

To create a secure experience, users are only shared via a web request from your secure backend to the user's carrier's secure backend and includes the user's attributes.

User information is only shared with Service Providers upon user consent. Users are able to choose whether to share their data and specifically what data will be shared with you.

2.0 Getting Started

To get started integrating the ZenKey with your applications, there are a few things you should do:

  • Register your application - Access the Service Provider portal to register your application and obtain a valid clientId and clientSecret.
  • Identify if you need custom redirect URIs - Redirect URIs will be used for callbacks to several ZenKey services
  • Identify user information data you want to capture - The ZenKey enrollment process includes asking for personal user data. The ZenKey service itself does not accumulate the personal data used for authentication. That data remains secured by the user's wireless carrier. Encrypted user information is only shared with Service Providers upon subscriber consent. Users are able to choose whether to share their data and specifically what data will be shared with each participating Service Provider.
    • Because applications must get authorization to access user information, "scopes" must be defined to allow actions. There are various user data scopes already defined in ZenKey which you can select to be captured during the enrollment process. Examples of these are email address, name and phone number. The scopes are used to verify users. OpenID is the only required scope and is added by default on every request when no scope is specified. If developers choose to specify scopes, they also must include OpenID. All others are optional depending on the needs of your application.
  • Decide to require PIN and/or Biometric - You can choose if you'd like to require the user to authenticate with a PIN and/or a biometric from their primary device (e.g. finger print, facial recognition, etc). In your setup, you can choose to have an experience with or without requiring both a PIN or biometric.

NOTE: The OpenID scope is required. Note: For Pre-Release: set up Git Access - While the SDK is under development (Pre-Release), we recommend maintaining the Provider SDK source code as a git submodule. If that is not possible, download the source here and place it in your project directory.

git submodule add https://github.com/MyZenKey/sp-sdk-android

2.1 ZenKey SDK Dependencies

The ZenKey SDK has the following dependency.

"com.android.support:customtabs:27.1.1"

If your application is using AndroidX, you will have to Jetify this dependency. For more information about migrating to AndroidX, see here.

If your application is using another version of the support library, you can force usage of your version. For more information about forcing dependency version, see here.

3.0 Add the ZenKey SDK

The ZenKey SDK is currently only provided as an AAR (Android Archive) file.

Here is how to import this AAR as a submodule for your Android project.

3.1 Import the AAR as sub-module in your Android project.

The AAR file can be imported as a module to your Android project. In order to achieve that, in Android right click on your project. In the dialog windows, select new > module.

Import SDK module Step 1

On the next dialog, select import .JAR/.AAR Package

Import SDK module Step 2

On the next dialog select the location of the AAR file and a name for the module.

Import SDK module Step 3

3.2 Add ZenKey SDK module as dependency in your application module

Finally add the module as a dependency to your application module (use the same module name that you used at the previous step) In addition, developers most also include the SDK dependency (See 2.1)

dependencies {
 implementation project(":zenkey-sdk")

 //If you use the support library, add the following dependency.
 implementation "com.android.support:customtabs:27.1.1"

 //If instead you use Androidx, add the following dependency.
 implementation "androidx.browser:browser:1.1.0"

}

4.0 Add the Internet permission.

If you don't already have the internet permission, add it in your Android manifest.

<manifest xmlns:android="http://schemas.android.com/apk/res/android">
    <uses-permission android:name="android.permission.INTERNET" />
    <application>
        [...]
    </application>
</manifest>

5.0 Register your clientId

The ZenKey SDK manifest contains a placeholder for your clientId. In order to compile your app with the ZenKey SDK, you must register the clientId placeholder value in your app build.gradle. Replace MY_CLIENT_ID by the value obtained in the previous step.

android {
    defaultConfig {
        manifestPlaceholders = [zenKeyClientId: 'MY_CLIENT_ID']
    }
}

6.0 Request Authorization Code

When making authorization requests, you can use the ZenKey default button that handles the interaction with the identityProvider and starts the authorization intent. This is done by adding ZenKeyButton to your layout or you can get the authorization intent from identityProvider.

6.1 Using ZenKeyButton

The ZenKey SDK provides a default button which will take care of the interaction with the identityProvider and start the authorization intent.

6.1.1 Add ZenKeyButton Inside Layout

To use the ZenKey button, add the following to your XML layout.

         <com.xci.zenkey.sdk.widget.ZenKeyButton
             android:id="@+id/zenKeyButton"
             android:layout_width="match_parent"
             android:layout_height="wrap_content"/>

6.1.2 Button Style

You can customize the appearance of the button. A dark button style is appropriate to use with light backgrounds. By default, the ZenKey SDK uses the dark style. The dark button style looks like this:

ZenKey Button Dark

The light button style is appropriate to use with dark backgrounds. The light button style looks like this:

ZenKey Button Light

6.1.2.1 Set Button Style in XML

To set the button style in XML, add the auto resolution namespace to the main container layout xmlns:app="http://schemas.android.com/apk/res-auto", then add the parameter app:mode="LIGHT" as follows:

        <com.xci.zenkey.sdk.widget.ZenKeyButton
              android:id="@+id/zenKeyButton"
              android:layout_width="match_parent"
              android:layout_height="wrap_content"
              app:mode="LIGHT"/>

6.1.2.2 Set Button Style Programmatically

To set the button style programmatically, call the zenKeyButton.setMode(ZenKeyButton.Mode.LIGHT) method on your ZenKeyButton.

public class MyActivity extends AppCompatActivity {
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.my_layout);
        ZenKeyButton zenKeyButton = findViewById(R.id.myZenKeyButton);
        zenKeyButton.setMode(ZenKeyButton.Mode.LIGHT);
    }
}

6.1.3 Button Text

The ZenKey button offers two text options, Sign In with Zenkey and Continue with Zenkey. The ZenKey button uses Sign In with ZenKey by default.

6.1.3.1 Set Button Text in XML

To set the button text in XML, add the auto resolution namespace to the main container layout xmlns:app="http://schemas.android.com/apk/res-auto", then add the parameter app:text="CONTINUE" as follows:

        <com.xci.zenkey.sdk.widget.ZenKeyButton
              android:id="@+id/zenKeyButton"
              android:layout_width="match_parent"
              android:layout_height="wrap_content"
              app:text="CONTINUE"/>

6.1.3.2 Set Button Text programmatically

To set the button text programmatically, call the zenKeyButton.setText(ZenKeyButton.Text.CONTINUE) method on your ZenKeyButton.

public class MyActivity extends AppCompatActivity {
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.my_layout);
        ZenKeyButton zenKeyButton = findViewById(R.id.myZenKeyButton);
        zenKeyButton.setText(ZenKeyButton.Text.CONTINUE);
    }
}

6.1.4 Set Fragment (if used inside fragment)

If you use the ZenKey Button inside a fragment, you must set this fragment to the ZenKeyButton, in order to receive the result inside the Fragment onActivityResult() method. Otherwise, the result will be received in the onActivityResult() method of the host activity.

public class MyFragment extends Fragment {
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.my_layout);
        findViewById(R.id.myZenKeyButton).setFragment(this);
    }
}

6.1.5 Set Scopes (optional)

By default, authorization requests made with the ZenKey SDK include the scope OpenId. For additional scopes using the ZenKeyButton, you set them as follows:

public class MyActivity extends AppCompatActivity {
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.my_layout);
        findViewById(R.id.myZenKeyButton).setScopes(Scopes.EMAIL, Scopes.fromValue("Any"));
    }
}

6.1.6 Set Custom Request Code (optional)

Optionally, you can set the request code as follows:

public class MyActivity extends AppCompatActivity {

    private int MY_REQUEST_CODE = 9;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.my_layout);
        findViewById(R.id.myZenKeyButton).setRequestCode(MY_REQUEST_CODE);
    }
}

6.2 Using IdentityProvider

You can make authorization requests, using identityProvider, but we recommend using ZenKeyButton (the ZenKey default button that handles the interaction with the identityProvider and starts the authorization intent).

If using identityProvider, to obtain authorization intent you call ZenKey.identityProvider().authorizeIntent().build().

The intent obtained from the identityProvider must be started using Activity.startActivityForResult(Intent, Int). You can use any request code of your choice.

public class MyActivity extends AppCompatActivity {

    private static final int REQUEST_CODE_ZENKEY = 1234;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
       super.onCreate(savedInstanceState);
       setContentView(R.layout.my_layout);
       findViewById(R.id.myZenKeyButton).setOnClickListener(v -> startZenKeyAuthorization());
    }

    private void startZenKeyAuthorization(){
        startActivityForResult(
                ZenKey.identityProvider()
                    .authorizeIntent()
                    .withScopes(Scopes.EMAIL, Scopes.ADDRESS)
                    .build(),
                REQUEST_CODE_ZENKEY);
    }
}        

7.0 Handle Authorization Response

To handle the authorization response, refer to the following:

7.1 Using OnActivityResult()

If developers do not specify any PendingIntents for their request, the result will coming back in the requesting activity/fragment onActivityResult() method. Developers can then call AuthorizationResponse.fromIntent(data) passing the data result intent to obtain the AuthorizationResponse.

public class MyActivity extends AppCompatActivity {

    private static final int REQUEST_CODE_ZENKEY = 1234;

    protected void onActivityResult(int requestCode, int resultCode, Intent data) {
       if (requestCode == REQUEST_CODE_ZENKEY) {
          if (resultCode == RESULT_OK) {
              handleAuthorizationResponse(data);
          } else {
             //Authorization canceled by user.
          }
       }
    }

    private void handleAuthorizationResponse(Intent data) {
       AuthorizationResponse response = AuthorizationResponse.fromIntent(data);
       if(response.isSuccessful()){
          //Authorization Succeed
          finishZenKeyAuthentication(response);
       } else {
           //Authorization Failed
           handleZenKeyError(response);
       }
    }

    private void finishZenKeyAuthentication(AuthorizationResponse response) {
       String authorizationCode = response.getAuthorizationCode();
       String mcc = response.getMcc();
       String mnc = response.getMnc();
       //Send those three values to your back-end to finish the authentication process.
    }

    private void handleZenKeyError(AuthorizationResponse response) {
       AuthorizationError error = response.getError();
       switch (error){
          case AuthorizationError.INVALID_CONFIGURATION:
             break;
          case AuthorizationError.INVALID_REQUEST:
             break;
          case AuthorizationError.REQUEST_DENIED:
             break;
          case AuthorizationError.REQUEST_TIMEOUT:
             break;
          case AuthorizationError.SERVER_ERROR:
             break;
          case AuthorizationError.NETWORK_FAILURE:
             break;
          case AuthorizationError.DISCOVERY_STATE:
             break;
          case AuthorizationError.UNKNOWN:
             break;
       }
    }
}

7.2 Using PendingIntent(s)

The ZenKey SDK allows developers to specify PendingIntents to start depending of the authorisation state or result. Developers can specify PendingIntents to start in case of successful or failing authorization responses.

public class MyActivity extends AppCompatActivity {

    private static final int REQUEST_CODE_ZENKEY = 1234;

    private void startZenKeyAuthorization(){
        startActivityForResult(
                ZenKey.identityProvider()
                    .authorizeIntent()
                    .withSuccessIntent(PendingIntent.getActivity(this, Activity.RESULT_OK, new Intent(this, SuccessActivity.class), PendingIntent.FLAG_UPDATE_CURRENT))
                    .withFailureIntent(PendingIntent.getActivity(this, Activity.RESULT_OK, new Intent(this, FailureActivity.class), PendingIntent.FLAG_UPDATE_CURRENT))
                    .build(),
                REQUEST_CODE_ZENKEY);
    }
}        

Alternately, Developers can specify a PendingIntents to start in case of completion. This PendingIntent is ignored if the above PendingIntents are specified as well.

public class MyActivity extends AppCompatActivity {

    private static final int REQUEST_CODE_ZENKEY = 1234;

    private void startZenKeyAuthorization(){
        startActivityForResult(
                ZenKey.identityProvider()
                    .authorizeIntent()
                    .withCompletionIntent(PendingIntent.getActivity(this, Activity.RESULT_OK, new Intent(this, CompletionActivity.class), PendingIntent.FLAG_UPDATE_CURRENT))
                    .build(),
                REQUEST_CODE_ZENKEY);
    }
}        

Developers can also specify a PendingIntent to start in case of cancellation.

public class MyActivity extends AppCompatActivity {

    private static final int REQUEST_CODE_ZENKEY = 1234;

    private void startZenKeyAuthorization(){
        startActivityForResult(
                ZenKey.identityProvider()
                    .authorizeIntent()
                    .withCancellationIntent(PendingIntent.getActivity(this, Activity.RESULT_CANCELED, new Intent(this, CancellationActivity.class), PendingIntent.FLAG_UPDATE_CURRENT))
                    .build(),
                REQUEST_CODE_ZENKEY);
    }
}        

Then inside the started activity, the developer can obtain the AuthorizationResponse using AuthorizationResponse.fromIntent(intent) passing the intent which started the activity as parameter.

public class MyResultActivity extends AppCompatActivity {

    @Override
        protected void onCreate(Bundle savedInstanceState) {
           super.onCreate(savedInstanceState);
           AuthorizationResponse response = AuthorizationResponse.fromIntent(getIntent());
        }
}        

8.0 Using a Custom Redirect URI (Optional)

By default, the ZenKey SDK uses and registers a default redirect URI. The value of the default redirect URI is <clientId>://com.xci.provider.sdk. For every request made using the ZenKey SDK, the corresponding AuthorizationResponse contains the redirect URI used for the request.

If you need to use a custom redirect URI, you must override the default value in your manifest, and specify the custom redirect URI for your request, using the ZenKeyButton or the IdentityProvider. Your custom redirect URI must be a valid redirect URI. For more information about URI validity check here.

8.1 Override the default Redirect URI in manifest

<activity android:name="com.xci.zenkey.sdk.RedirectUriReceiverActivity"
            tools:node="replace">
    <intent-filter>
        <action android:name="android.intent.action.VIEW"/>
        <category android:name="android.intent.category.DEFAULT"/>
        <category android:name="android.intent.category.BROWSABLE"/>
        <data android:scheme="com.mydomain" android:host="authorize"/>
    </intent-filter>        
</activity>

8.2 Set the Custom Redirect URI for your request

Set the Custom Redirect URI using the ZenKeyButton

If you use the ZenKeyButton, you set the custom Redirect URI as follows:

public class MyActivity extends AppCompatActivity {
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.my_layout);
        ZenKeyButton zenKeyButton = findViewById(R.id.myZenKeyButton);
        zenKeyButton.setRedirectUri(
                new Uri.Builder()
                    .scheme("com.mydomain")
                    .authority("authorize")
                    .build());
    }
}

Set the Custom Redirect URI using the IdentityProvider

If you use the IdentityProvider, you set the custom Redirect URI as follows:

public class MyActivity extends AppCompatActivity {

    private static final int REQUEST_CODE_ZENKEY = 1234;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
       super.onCreate(savedInstanceState);
       setContentView(R.layout.my_layout);
       findViewById(R.id.myZenKeyButton).setOnClickListener(v -> startZenKeyAuthorization());
    }

    private void startZenKeyAuthorization(){
        startActivityForResult(
                ZenKey.identityProvider()
                    .authorizeIntent()
                    .withRedirectUri(new Uri.Builder()
                                       .scheme("https")
                                       .authority("app.example.com")
                                       .path("/oauth2redirect")
                                       .build())
                    .build(),
                REQUEST_CODE_ZENKEY);
    }
}        

8.3 HTTP/HTTPS Redirect URI

HTTPS redirects are more secure and preferred over HTTP. If an HTTP/HTTPS redirect URI is required instead of a custom scheme, use the same approach and modify your AndroidManifest.xml:

<activity android:name="com.xci.zenkey.sdk.RedirectUriReceiverActivity"
        tools:node="replace">
    <intent-filter>
        <action android:name="android.intent.action.VIEW"/>
        <category android:name="android.intent.category.DEFAULT"/>
        <category android:name="android.intent.category.BROWSABLE"/>
        <data android:scheme="https"
              android:host="www.example.com"
              android:pathPrefix="/oauth2redirect"/>
    </intent-filter>
</activity>

8.4 Handling with IdentityProvider

If you use the identityProvider instead of the ZenKeyButton, you set the Redirect URI like this:

public class MyActivity extends AppCompatActivity {

    private static final int REQUEST_CODE_ZENKEY = 1234;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
       super.onCreate(savedInstanceState);
       setContentView(R.layout.my_layout);
       findViewById(R.id.myZenKeyButton).setOnClickListener(v -> startZenKeyAuthorization());
    }

    private void startZenKeyAuthorization(){
        startActivityForResult(
                ZenKey.identityProvider()
                      .authorizeIntent()
                      .withRedirectUri(
                              new Uri.Builder()
                                  .scheme("com.example.app")
                                  .authority("authority")
                                  .build())
                      .build(),
                REQUEST_CODE_ZENKEY);
    }
}        

For more information, see the following:

9.0 Error Handling

The Error Type identifies the class of AuthorizationError. For more details, refer to the ERROR_KEY and ERROR_DESCRIPTION_KEY.

The following table summarizes the AuthorizationError error types and potential recovery suggestions for each.

Error Type Possible Cause Recovery Suggestion
INVALID_CONFIGURATION The wrong client_id was registered. Revise the client_id.
INVALID_REQUEST An invalid parameter was used for the current request. Check the request parameters.
REQUEST_DENIED This might occur when the user doesn't click deny/cancel Display an appropriate feedback message to the user
REQUEST_TIMEOUT The request took too long to process and is cancelled on the client side. This is not related to the server but to the device network connection (such as a bad connection). Use a feedback message such as "Unable to reach the server, please try again" or "Poor network connection..."
SERVER_ERROR The server was not able to handle the request. Check your server. This is not a network issue.
NETWORK_FAILURE There is no connection with the network. Display a feedback message advising the user to check their connection and try again.
DISCOVERY_STATE Triggered by the SDK during the discovery process. Examples: When the SDK is doing a loop between discovery and discover_ui because of a server bug, or when there is no browser available on the device to show the discover_ui/authorize webpages. Try to perform the authorization request again.
UNKNOWN An unknown error has occurred. If the problem persists, contact support.

9.1 Debugging

The SDK is offering a logging mechanism to help with integration and debugging. Logs are disabled by default, in order to activate the logs, developers can call the following method. The best place to enable the logs is in your application class if you have one, or in class before an actual request is started.

public class MyClass {

    public void myMethod(){
        ZenKey.logs(true);
    }
}

10.0 Account Migration

Migration will be supported in a future release.

When users change carriers, ZenKey provides you with the support you need. This section describes the migration process and best practices.

10.1 Migration Process

Take a look at the various interactions between user, Service Provider, carrier and ZenKey when a user ports his/her account from one carrier to another.

Sample User Account Attributes

  • Phone's Internal Sub= 001001-carrierid
  • Phone=555
  • User has visited at least one Service Provider
  • SP sees a SUB=001001-B
  • SP has created a user federated to verify=001001-B

Process Flow

  1. The user migrates phone 555 from mobile provider MNO1 to MNO2 by keeping the current device but changing the SIM.

  2. After migrating the phone number from the carrier to carrier (e.g., within 15 minutes), the user tries to connect to a Service Provider app, and the SP triggers a login prompt with the phone number.

  3. The SP SDK submits a discovery request with the new mccmnc to retrieve the OpenID configuration for MNO2.

  4. The SP SDK constructs the authentication URL to MNO, opening in the device browser to MNO2's web authentication endpoint.

  5. MNO2 sees the mobile user agent and posts a banner encouraging the user to download the CCID app.

  6. The user downloads, installs, and launches the CCID application for MNO2 .

  7. MNO2 notices that the user is not yet registered for the new phone number and:

    a. Asks: “Would you like to register a CCID?” or “Would you like to PORT your CCID from your previous MNO?”

    b. Upon seeing that the device has a recently migrated phone line, offers a migration option.

  8. The user selects the option to migrate the existing CCID and is redirected in a WebView to MNO1’s authentication endpoint. (Because the MNO1 authentication request contains the port_data scope, MNO1 knows the authentication is for migration.)

  9. MNO1 completes the user authentication before returning the user to MNO2: a. MNO1 may require the user to perform multiple recovery methods because EAP-AKA (SIM) authentication will not work for the user. b. MNO1 signs a port token for each SP using the slow rotating key present in the OpenID configuration reference.

  10. The user completes MNO2 account setup steps:

    a. MNO2 prepopulates the registration page with the previous name, email, address, etc.

    b. The user chooses a new pin.

    c. MNO2 stores port tokens for each of the previous Service Providers used at MNO1.

  11. MNO2 asks if the user wants to port his/her previously-defined consents for each of the SPs, and then returns the user to the Service Provider application with an authentication code.

  12. The Service Provider issues an access_token and id_token:

    • SUB=002002-Z
    • AKA: port_token: signedjwt {old sub : 001001-B }
  13. The Service Provider does not recognize this suband instead uses the ISS to access MNO1’s port_token signing key, and verifies the signature of the port_token.

  14. The Service Provider updates the user's subin its database with the new value. For example, from 001001-B to 002002-Z.

10.2 Migration Best Practices

When an SP first authenticates a user, the first id_token should contain a single subject claim. The SP should store this as a reference rather than a phone number or email address which could later change.

If an SP receives a new id_token that contains an AKA claim and an unrecognized sub, the SP should take the following steps:

  1. Open the AKA port_token.
  2. Verify the port_token issuer is a trusted carrier. NOTE: The SP portal will contain a list of valid iss URLs.
  3. Use the port_token :iss value to extract the OpenID configuration` of the old MNO.
  4. Use the OpenID configuration to extract the JWKs for the old MNO.
  5. Use the key ID (KID) in the port_token to identify which JWK key to use to verify the token's signature.
  6. If the SP has a recorded a user with the old subject, update the references to the new subject from the new carrier.

Note: Because a user may choose to not port his/her CCID user account, or change carriers by getting a new phone number with the new carrier, the Service Provider should host methods to update the CCID references.

Next Steps

On your secure server, perform discovery and use the discovered token endpoint to request an access token from ZenKey with the processes already detailed:

  • Auth Code
  • MCC (Mobile Country Code)
  • MNC (Mobile Network Code)
  • Redirect URI

The token should be used as the basis for accessing or creating a token within the domain of your application. After you exchange the authorization code for an access token on your secure server, you will be able to access the ZenKey userinfo endpoint, which will pass information through your server's authenticated endpoints as defined by your application.

Information on setting up your secure server can be found in the ZenKey Server and Web Integration Guide.

Support

For technical questions, contact techsupport@myzenkey.com.

License

Copyright © 2019 XCI JV, LLC.

Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License.

NOTICE: © 2019 XCI JV, LLC. ZENKEY IS A TRADEMARK OF XCI JV, LLC. ALL RIGHTS RESERVED. THE INFORMATION CONTAINED HEREIN IS NOT AN OFFER, COMMITMENT,REPRESENTATION OR WARRANTY AND IS SUBJECT TO CHANGE

Last Update: Document Version 0.9.15 - October 18, 2019