Authentication

Every user has to authenticate with Layer before using any Layer functionality. Authenticating with Layer may happen separately from logging into your app (especially if your app has functionality beyond messaging). There is also a corresponding deauthenticate action for authenticated users.

Best practice If your app supports multiple users on a single device, Layer allows each user to send and receive their own messages. Just make sure to deauthenticate Layer when a user logs out of your app, wait for the deauthentication to complete, and run through the authentication flow again.

Layer implements a federated authentication flow, which means that it’s up to you to verify user login credentials, and then tell Layer that the user should be authenticated. This means that you must provide a custom service to verify user credentials. We do not provide this functionality.

At a high level, there are three main steps in the authentication flow:

  1. You request a nonce from Layer, which is a unique string used to identify a single authentication request.
  2. You send the nonce, along with the user’s login credentials, to your login backend.
  3. If the login credentials are correct, you generate an identity token and send it back to Layer.

We will verify your identity token, and if it looks good, we’ll let your app know that it has been authenticated. The whole flow looks like this:

Authentication flow diagram for Android

Note

Nonces are only intended to be used once. Furthermore, they expire 10 minutes after they’ve been generated. For this reason, we recommend you do not store nonces anywhere. If you attempt to use a nonce that has been used or that has expired, the authentication flow will fail.

You can request a nonce at any point, as often as you’d like.

Your app can begin the authentication flow at any point before you try to load conversations or send/receive messages. If your app has captured user credentials at some other point, the entire flow can occur in the background without any user intervention.

Authenticating

Layer first has to be connected before we authenticate. After connecting, the ConnectionListener.onConnectionConnected() method will be called, and you can execute layerClient.authenticate() at that point.

@Override
 // Called when the LayerClient establishes a network connection
 public void onConnectionConnected(LayerClient layerClient) {
     // Ask the LayerClient to authenticate. If no auth credentials are present,
     // an authentication challenge is issued
     layerClient.authenticate();
 }

Once you have called the authenticate() method, your application will receive a call to your LayerAuthenticationListener's onAuthenticationChallenge() method. You can use the following implementation as a template to connect to your own backend, which needs to return an Identity Token.

/*
 * 1. Implement `onAuthenticationChallenge` in your Authentication Listener to acquire a
 *    nonce. Each nonce is valid for 10 minutes after creation, after which you will have
 *    to call authenticate() again to generate a new one.
 */

public void onAuthenticationChallenge(final LayerClient layerClient, final String nonce) {

  /*
   * 2. Connect to your Identity Web Service to generate an Identity Token. In addition
   *    to your Layer App ID, User ID, and nonce, you can choose to pass in any other
   *    parameters that make sense (such as a password), depending on your App's login
   *    process.
   */

   String eit = generateToken(appID, userID, nonce);

  /*
   * 3. Submit identity token to Layer for validation
   */

   layerClient.answerAuthenticationChallenge(eit);
}

The final step is the verify that authentication completed successfully, or handle any errors:

// Called if there was a problem authenticating
// Common causes include a malformed identity token, missing parameters in the identity
// token, missing or incorrect nonce
public void onAuthenticationError(LayerClient layerClient, LayerException e) {
    // Handle the case where the User ID could not be Authenticated
    System.out.println("There was an error authenticating: " + e);
}

// Called when the user has successfully authenticated
public void onAuthenticated(LayerClient client, String userID) {
    // Handle the case where the User ID was Authenticated correctly (start the
    // Conversation Activity, for example)
    System.out.println("Authentication successful");
}

Best practice We recommend putting the code to connect and authenticate in only one place. This could be in your main Activity if your app is purely messaging, or in a LayerController class or something similar.

Identity token

The identity token in the code above comes from your server. Your backend should generate this token when you provide it with valid authentication credentials for your users (typically username/email and password, although it can be a phone number or some other identifier as well). Typically, your app would request this information from the user, and pass it to your server. Your server will also need to know your Layer app ID, which you can either hard-code on the server, or pass up from the app. Finally, you will also need to pass up the nonce from the client to your server.

Common mistake

Make sure you are not modifying or processing the nonce in any way. Note that nonces are already URL-safe. Often, developers will (accidently or otherwise) url-decode the nonce, which results in plus signs (+) in the nonce being converted into spaces. This breaks the identity token.

An identity token is a JSON Web Token that describes the account details of a user within your application. The identity token consists of two parts, both JSON objects — a header (known as a “JOSE Header”) and the account details (known as the “JWT Claims Set”). These two parts are combined into a single string. This is the structure of both parts:

// JOSE Header
{
  "typ": "JWT", // String: Indicates a MIME Type of application/JWT
  "alg": "RS256", // String: Indicates the type of algorithm used to sign the token. Must be RS256
  "cty": "layer-eit;v=1", // String: Indicates a Content Type of Layer External Identity Token, version 1
  "kid": "layer:///keys/cd8c286e-f2e4-11e5-99fe-eecb000000b0" // String: Layer Key ID used to sign the token.
}

// JWT Claims Set
{
  "iss": "layer:///providers/cf0eb712-d9ab-11e5-b6a9-c01d00006542", // String: The Layer Provider ID
  "prn": "APPLICATION USER ID", // String: The ID you use to identify the user. Could be a username, email, or user ID value
  "iat": 1461023254, // Integer: Time the token was generated as an epoch timestamp
  "exp": 1461023314", // Integer: An arbitrary time in the future when this token should expire. Also an epoch timestamp
  "nce": "abcNONCE123", // String: The nonce obtained from the client.
  "first_name" : "Firstname", // Optional String: First name for the user
  "last_name" : "Lastname", // Optional String: Last name for the user
  "display_name" : "displayname", // Optional String: The name to show onscreen for the user
  "avatar_url" : "https://example.com/image.jpg" // Optional String: URL to profile photo for the user
}

You can get the Authentication Key (used for the kid field in the header) and the Provider ID (used for the iss field in the claims) from the Developer Dashboard.

Note

You determine when the token becomes invalid by setting the expiration time (exp field). If we receive your token after this expiration time, authentication will fail. However, it does not affect any other client behavior — notably, users will not be logged out when the identity token expires.

We recommend setting the expiration time at least 30 seconds into the future. It doesn’t make sense to set it further than 10 minutes into the future, as the nonce will have expired by that point. It doesn’t make sense to cache/save the identity token in your database for the same reason.

An identity token is sent back as a securely signed string, which looks nothing like the original JSON. This can be difficult to do correctly. Fortunately, prebuilt JWT libraries are available for many languages:

To make this easier, we provide sample backends:

There are also third-party libraries that generate identity tokens for you. Note that we cannot provide support for these libraries:

If you built your own library and want to be included in this list, send an email to support@layer.com.

Best practice

If you have an issue with your identity token, please make sure it is valid before contacting support.

We provide a validation tool to help you make sure all the parts of your token are valid. To use, generate an identity token from your backend and paste it into the tool. We’ll let you know if it looks good or not.

Note that this tool does not check your token’s expiration time, or whether your nonce has expired.

The validation tool is available from the Developer Dashboard.

Deauthenticating

Deauthenticating with Layer “logs out” the user from Layer, preventing them from sending and receiving messages or notifications. Depending on what your app does, this could happen separately from logging out of your app itself.

By default, deauthenticating will delete locally stored data (which includes the user’s conversations and messages). You can optinally specify LayerClientImpl.DeauthenticationAction.KEEP_LOCAL_DATA to keep the data in device. When the same user authenticates again, this data will be used and helps conserve bandwidth.

You can deauthenticate at any point in your app by calling layerClient.deauthenticate().

// Called after the user has been deauthenticated
public void onDeauthenticated(LayerClient client) {
    // Handle the case where the user deauthenticated (return to your App's login
    // screen, for example)
    System.out.println("User is deauthenticated");
}

Note

Deauthenticating does not happen instantly. Don’t do anything Layer-related (including authenticating a new user) until onDeauthenticated has been called.

Connecting Identities