Server and Web Integration Guide

This guide is for developers integrating ZenKey into their Web applications as well as backend services for clients.

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 (SPs) is a better user experience and a more secure link to 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 to authenticate into all of your apps and websites (when those third parties have enabled ZenKey). These user flows can take place on the user's primary device, which has the ZenKey app installed, or on a secondary device, such as desktops and tablets.

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).

High-level Architecture on a Primary Device

Primary Device Flow

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

Step 2: The 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 3.1.1: Redirect User-Agent).

Step 3: Your backend server may make a token request for user info or other resources which the user consented to share with you.

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 or desktop. These secondary devices rely on the user's primary device 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. From there, they are then instructed to open the ZenKey application on their primary device, where they will be able to complete the authentication request.

High-level Architecture on a Secondary 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, receives the auth code back at your Redirect URI.

Step 5: Your backend server may make a token request for user info or other resources which the user consented to share with you.

1.3 User Data

To create a secure experience, user info is only shared via a web request from your secure backend to the user's carrier backend. By using a backend server to make calls to the user's carrier, and not the client application, the clientId, clientSecret and user ID token are not revealed to your client.

The ZenKey services 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 user consent. Users are able to choose whether to share their data and specifically what data will be shared with each participating Service Provider.

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 user information data you want to capture - The ZenKey enrollment process includes asking for personal user data. The ZenKey services 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. There are various user data "scopes" already defined in the ZenKey which you can select to be captured during the enrollment process, such as email address, name, phone number.
  • 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. These scopes are used to verify users. OpenID is the only required scope and is added by default on every request. All others are optional depending on the needs of your application.
  • Identify if you need custom redirect URIs - Redirect URIs will be used for callbacks to several ZenKey services.
  • 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.

2.1 Integration Options

In order to support all possible backend technology stacks, ZenKey does not provide SDKs for specific languages or frameworks. Instead, this guide describes the HTTP request flow required to integrate with ZenKey.

We strongly recommend that you leverage an OIDC certified relying party library to abstract away the implementation details of OIDC authentication. Find one here

To aid in the implementation, we provide example applications in several popular languages and frameworks:

3.0 Authentication Flow

The web and server implementation supports authorization on both primary and secondary devices.

If you are implementing ZenKey on a website, the authentication flow begins with a carrier Discovery UI. After a user clicks the ZenKey button on your site, they are taken to a web page that contains a visual and numeric code used to link the web request to the ZenKey application on their primary device.

When supporting iOS and Android implementations, the SDK handles carrier Discovery UI. The step is either skipped, because the app is on the user's primary device, or automatically invoked.

3.1 Carrier Discovery UI

Section 3.1 and it's subsections are handled by the iOS or Android SDK within your application on a user's primary device.

The Carrier Discovery UI web page presents the user with a visual and numeric code. The user is prompted to open the ZenKey application on their primary device to authorize the request. If the user is on a device with a SIM card installed, they will be prompted to choose their carrier before preceeding in to the ZenKey app of through the visual code flow outlined above.

The first time a user goes through this step on a device, they create a link between the browser and their ZenKey account known as a Trusted Browser. On subsequent requests to authenticate on that browser, the user will skip the visual and numeric code flow. Instead a push notification will be sent to their primary device, allowing for a more seamless approval of the request.

ZenKey handles all of the logic associated with which of these two Carrier Discovery UI experiences the user should be presented.

3.1.1 Redirect User-Agent

The carrier's DISCOVERY_UI endpoint brings the user to ZenKey's carrier discovery UI, where they then see a visual code or select their carrier's logo.

https://discoveryui.myzenkey.com/ui/discovery-ui?
    client_id=CLIENT_ID
    &redirect_uri=REDIRECT_URI
    &state=STATE
    &sdk_version=SDK_VERSION
    &prompt=true
Parameter Description
CLIENT_ID Your ZenKey clientId obtained in the SP Portal.
REDIRECT_URI ZenKey redirects user back to your app using this URL. The URL will contain an authorization code that your app can exchange for a token. The Redirect URI must be registered to your clientId.
STATE An anti-forgery state token. Generate a unique session token and store it. You will need to match this token with the authentication response to verify that the user is making the request, and not a malicious attacker. (Optional.)
SDK_VERSION Method for the SDK to report version. (Optional.)
PROMPT UI will ignore previous cookies so user can reselect carrier. Prompt may be needed if user has ported to a new carrier and their secondary device has failed authentication with old MNO. SP may re-trigger discovery, forcing UI. (Optional.)

3.1.2 Response

The user is now redirected to your REDIRECT_URI, whose URL also contains the parameters LOGIN_HINT_TOKEN, MCCMNC and STATE. For example:

https://server.example.com/cb?login_hint_token=<xxx>&mccmnc=<xx>&state=<state>

The LOGIN_HINT_TOKEN will be used in the Authorization Code request (see Section 3.3); the MCCMNC during the OIDC Discovery request (see Section 3.2); and STATE for validating whether its returned value matches the one sent in the request.

Parameter Description
LOGIN_HINT_TOKEN This will only be returned if the request is made by a secondary device, such as a desktop or tablet. Requests that originate on a user's primary device will not return this parameter.
MCCMNC Six digit code that identifies the user's carrier and resides on every SIM card. You will need to store this for subsequent calls.
STATE Validate against the token generated earlier.

3.2 OIDC Discovery

Section 3.2 and it's subsections are handled by the iOS or Android SDK within your application on a user's primary device.

Perform OIDC Discovery to fetch the OpenID Configuration Document for the user's carrier. This call will provide information about the carrier's OpenID configuration, including all necessary endpoints and public key location information. Use https://discoveryissuer.myzenkey.com/.well-known/openid_configuration as the DISCOVERY_URL variable in your implementation.

3.2.1 Request

https://discoveryissuer.myzenkey.com/.well-known/openid_configuration?
    client_id=CLIENT_ID
    &mccmnc=MCCMNC
Parameter Description
CLIENT_ID Obtained in the ZenKey Service Provider Portal.
MCCMNC Six digit code that identifies the user's carrier and SIM card details.
SUB Pairwise identifier that ties a user to an SP CLIENT_ID. (Optional.)
PHONE_NUMBER Only when a valid CLIENT_ID and CLIENT_SECRET are present may the SP request discovery via the phone number.* (Optional.)
IP SP webserver may make a discovery request passing client's IP. (Optional.)

For discovery requests made *only with a PHONE_NUMBER, you may use the "proof of possession" signature Header: x-authorization.

3.2.2 Discovery Response

The carrier's discovery response will contain the OpenID Configuration Document. Ensure that you fetch the OpenID Configuration Document on each authentication request, as it differs based on the user's carrier. Below is a snippet of what a carrier might return:

HTTP/1.1 200 OK
Content_type: application/json
Cache-control: max-age=864000

  {
   "issuer":"https://mno.com",
   "authorization_endpoint":"https://mno.com/connect/authorize",
   "token_endpoint":"https://mno.com/connect/token",
   "userinfo_endpoint":"https://mno.com/connect/userinfo",
   "registration_endpoint":"https://xcijv.com/connect/register",
   "scopes_supported":["openid", "profile", "email", "address", "phone", ".."],
   "response_types_supported":["code", "async_token” ],
   ...
  }

3.3 Request Authorization Code

Section 3.3 and it's subsections are handled by the iOS or Android SDK within your application on a user's primary device.

When you request an authorization code, it will be to the carrier's AUTHORIZATION_ENDPOINT returned in the discovery response. Also included in your auth code request will be the REDIRECT_URI created when you retrieved your CLIENT_ID and CLIENT_SECRET in the ZenKey Service Provider Portal as well as several other parameters listed below.

https://AUTHORIZATION_URL?
    client_id=CLIENT_ID
    &login_hint_token=LOGIN_HINT_TOKEN
    &redirect_uri=REDIRECT_URI
    &response_type=code
    &scope=SCOPES
    &state=STATE
    &acr_values=ACR_VALUES
Parameter Description
AUTHORIZATION_URL The carrier's authorization endpoint from the OpenID Configuration Document.
CLIENT_ID Obtained in the ZenKey Service Provider Portal.
LOGIN_HINT_TOKEN The LOGIN_HINT_TOKEN from the carrier Discovery UI response.
REDIRECT_URI The URL in your app that ZenKey will redirect the user back to. Will contain an authorization CODE that your app can exchange for a token. Must exactly match the value specified during registration in SP Portal.
STATE Token generated earlier.
SCOPES User attributes like name, email, phone, and address.
ACR_VALUES Authentication levels (e.g. aal1 aal2 aal3) based on how and how often the SP wants their users to authenticate. Parameter will return the first value user has achieved. (Optional.)

3.3.1 Authorization Response

The user-agent will now be redirected to the specified REDIRECT_URI with these URL parameters.

Parameter Description
CODE Used in Token Request.
STATE Validate value against the token generated earlier.
MCCMNC Needed for SP client to inform SP server of carrier.
CORRELATION_ID Tracking ID used for transaction logging. Defined by SP issuing request. SP must use Service Portal to access log entries.
ERROR Standard OpenID Connect error code returned.
ERROR_DESCRIPTION Human-readable ASCII encoded text description of the error. For instance: “User is on a carrier not yet integrated with ZenKey”. For more info, refer to OIDC specs.

3.4 Token Request

Regardless of client (e.g. desktop, mobile app), all token requests should be performed from a secure server so as not to leak client credentials. Below is the body of a sample request to a carrier's token_endpoint:

POST /token HTTP/1.1
Host: mno.com
Authorization Basic Y2xpZW50aWQ6Y2xpZW50c2VjcmV0
Content-Type: application/json

{
    “grant_type”:“authorization_code”,
    “redirect_uri”=“www.client.com”,
    “code”:“i1WsRn1uB1”,
    “code_verifier”:“xxxxxxx”,
    “sdk_version”:“1.0”,
    “client_assertion_type":“urn:ietf:params:oauth:client-assertion-type:jwt-bearer”,
    “client_assertion":“PHNhadsfgdsagadfgag...ZT”
}
Parameter Description
TOKEN_URL The carrier's token endpoint from the OpenID Configuration.
GRANT_TYPE An authorization code or refresh token.
CODE The CODE from authorization code response.
CLIENT_ASSERTION_TYPE Defined by Service Provider.
CLIENT_ASSERTION Signed JWT.
REDIRECT_URI ZenKey redirects user back to your app using this URL.
CODE_VERIFIER Cryptographically random key for PKCE. (Optional.)
SDK_VERSION ZenKey SDK version (Optional.)

3.5 Token Response

The token request returns two important JSON Web Tokens: an ID_TOKEN and an ACCESS_TOKEN. The ACCESS_TOKEN provides access to the scopes via the user info endpoint. The ID_TOKEN contains claims about the user, such as their SUB, along with other authentication information. Along with these parameters, the carrier's TOKEN_ENDPOINT returns the following:

Parameter Description
ACCESS_TOKEN Bearer token used when making requests to carrier's USERINFO_ENDPOINT.
TOKEN_TYPE Set to "Bearer".
EXPIRES_IN Lifetime of current token.
SCOPE List of scopes user has approved for SP.
CORRELATION_ID Same value that was passed to the carrier in the request.
ID_TOKEN JWT containing user profile info and claims about their authentication, such as "iss", "sub", "iat", "aud", "nonce", "acr", etc.

3.6 Request User Info

To request user info, you will now use your access token by issuing a GET request from your backend to the carrier's USERINFO_ENDPOINT. Always make calls from your secure server to allow for safer transit of user info. A successful call will result in the carrier sharing the scopes your user approved during authorization.

    GET {USERINFO_ENDPOINT}
    Content-Type: application/json
    Authorization: Bearer {ACCESS_TOKEN}
    x-authorization: {<key_binding>}
Parameter Description
USERINFO_ENDPOINT Extracted from the discovered carrier’s openid-configuration.
ACCESS_TOKEN Bearer token when making requests to the userInfo endpoint.
x-authorization Key binding signature to prove possession of JWT.

3.7 User Info Response

The response will contain JSON with the user information requested by your scopes and approved by the user.

{
  "sub": "mccmnc-123456789",
  "name": "Jane Doe",
  "given_name": "Jane",
  "family_name": "Doe",
  "email": "janedoe@example.com",
  "email_verified":"true",
  "postal_code": "90210-3456",
  "phone_number": "+13101234567",
  "phone_number_verified":"true"
}

4.0 Account Migration

When users change carriers, ZenKey provides you with the support you need. This section describes how the migration process works and best practices for when a user ports his/her account from one carrier to another.

To see how account migration works with ZenKey, imagine a user with these initial traits:

  • phone=1234567890.

  • mccmnc=310010.

  • sub= 001001-{carrierid}.

Now imagine that the:

  1. User visits an SP with client_id=ccid-SP0001.

  2. SP detects the user as SUB=001001-B.

  3. SP stores/federates the user as verify=001001-B.

4.1 Migration Flow

Given this background, see how ZenKey helps you handle when a user migrates his/her account.

  1. The user migrates phone number 1234567890 from Mobile Network Operator #1 (MNO1) to Mobile Network Operator #2 (MNO2), keeping the device but changing SIM and mccmnc.

  2. The user migrates quickly (e.g., within 15 minutes), so when they try to use the SP with client_id=ccid-SP0001, that 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, 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 ZenKey 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 new ZenKey carrier account?” or “Would you like to PORT your prior ZenKey carrier account 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 ZenKey carrier account and is redirected in a WebView to MNO1’s authentication endpoint. (Note: port_data is a scope reserved for carriers only. It informs the carrier to render to the user a confirmation for porting the user identity account to a new carrier. Only carriers using ZenKey may access this scope.) 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. The access_token is the bearer token when making requests to the userinfo_endpoint. The id_token is a JSON Web Token (JWT) that contains claims about the authentication of an end user by an authorization server, such as sub=mncmcc-002002-Z.

  13. But the SP does not recognize this suband so uses the ISS (i.e. discovery endpoint) to access MNO1’s port_token signing key and verify the signature of the port_token. The port_token is always encoded. However once decoded, its contents will contain the new sub:

    {
        "iss": "https://zenkey.oldmno.com",
        "sub": "mncmcc-002002-Z",
        "iat": 1516239022,
        "aud": client_id
    }
  1. The Service Provider updates the user's sub in its database with the new value. For example, mncmcc-001001-B would become mncmcc-002002-Z.

4.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, since these are liable to change.

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

  1. Open the AKA port_token.
  2. Verify the port_token issuer is a trusted carrier. (The Service Provider 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 Service Provider 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.

5.0 Next Steps

In a database where you store information about your users, you should record the sub as the primary identifier of a ZenKey user because their phone_number and email may change.

Depending on whether the user is registering or signing in, you will want to create or fetch their user record from your data store, respectively. You may also choose to enrich this user record with information received from the User Info response.

Once you have completed the ZenKey authentication flow, return a session using the session management strategy you're already using for your application. Discard the tokens used throughout this flow.

6.0 Sign-In Buttons

You can use these buttons to begin the ZenKey sign in flow. They can be used on the web and other digital platforms. See the Android integration guide and iOS integration guide for information about using SDK buttons.

6.1 Button Variations

6.1.1 Colored and Light Buttons

The color version of the button should be used on white or light backgrounds. The light button variation should be used on dark backgrounds and in dark mode.

Color Light
Normal Normal, colored button Normal, light button
Focused Focused, colored button Focused, light button
Pressed Pressed, colored button Pressed, light button
Disabled Disabled, colored button Disabled, light button

6.1.2 CTA Variations

You may also use the "Continue" call to action if it is more suitable to your use case.

Color Light
Normal Normal, colored button Normal, light button
Focused Focused, colored button Focused, light button
Pressed Pressed, colored button Pressed, light button
Disabled Disabled, colored button Disabled, light button

6.1.3 Micro Buttons

Micro buttons should be used when space is limited. Because the button does not contain a call to action, the user interface must make the button's function clear.

Color Light
Normal ![Normal, colored button](./image/zenkey-buttons/color/enabled/no text.png) ![Normal, light button](./image/zenkey-buttons/white/enabled/no text.png)
Focused ![Focused, colored button](./image/zenkey-buttons/color/focused/no text.png) ![Focused, light button](./image/zenkey-buttons/white/focused/no text.png)
Pressed ![Pressed, colored button](./image/zenkey-buttons/color/pressed/no text.png) ![Pressed, light button](./image/zenkey-buttons/white/pressed/no text.png)
Disabled ![Disabled, colored button](./image/zenkey-buttons/color/disabled/no text.png) ![Disabled, light button](./image/zenkey-buttons/white/disabled/no text.png)

6.2 Button Usage Guidelines

Please use the provided versions of the buttons: avoid creating your own variations. Do not change the button colors or font.

Buttons may be resized as needed, but the ZenKey symbol should always remain left-aligned. The button call to action should be centered between the ZenKey symbol and the right edge. Prioritize the ZenKey sign-in button whenever possible.

The ZenKey buttons use #008522 green as a primary color. White (#FFFFFF) and black (#000000) are used as secondary colors.

Support

For technical questions, contact support.

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.

Revision History

Date Version Description
12.04.2019 0.9.17 Deleted License Notice.
12.04.2019 0.9.16 Revised parameter values to meet latest API spec.
11.27.2019 0.9.15 Updated multiple sections.
10.11.2019 0.9.13 Corrected Discovery UI URL
10.9.2019 0.9.12 Added updated Primary and Secondary device flow diagrams
10.4.2019 0.9.11 Added Account Migration Section
8.30.2019 0.9.10 Updated Background section; Better definition of variables; Clarified steps needed to support the ZenKey SDK in native applications.
8.20.2019 0.9.9 Added section numbers; Added revision history

Last Update: Document Version 0.9.17 December 4, 2019