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.

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 iOS

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.

Best practice

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

/*
 * 1. Request nonce from Layer.  Each nonce is valid for 10 minutes after
 *    creation, after which you will have to generate a new one.
 */
[layerClient requestAuthenticationNonceWithCompletion:^(NSString *nonce, NSError *error) {

   /*
    * 2. Connect to your backend to generate an identity token.
    */
    NSString *identityToken = ...

    /*
     * 3. Submit identity token to Layer for validation
     */
     [layerClient authenticateWithIdentityToken:identityToken completion:^(LYRIdentity *authenticatedUser, NSError *error) {
         if (authenticatedUser) {
             NSLog(@"Authenticated as User: %@", authenticatedUser);
         }
     }];
}];

Authentication Challenge

At any time during the lifecycle of a Layer client session the server may issue an authentication challenge and require the client to confirm its identity. When such a challenge is encountered, the client will immediately become deauthenticated and will no longer be able to interact with communication services until reauthenticated. The nonce value issued with the challenge must be submitted to the remote identity provider in order to obtain a new Identity Token.

Best practice

Put this code in your Layer client delegate class and implement the same authentication flow as before.

- (void)layerClient:(LYRClient *)client didReceiveAuthenticationChallengeWithNonce:(NSString *)nonce
{
    NSLog(@"Layer Client did receive an authentication challenge with nonce=%@", nonce);

   /*
    * 1. Connect to your backend to generate an identity token using the provided nonce.
    */
    NSString *identityToken = ...

   /*
    * 2. Submit identity token to Layer for validation
    */
    [layerClient authenticateWithIdentityToken:identityToken completion:^(LYRIdentity *authenticatedUser, NSError *error) {
        if (authenticatedUser) {
            NSLog(@"Authenticated as User: %@", authenticatedUser);
        }
    }];
}

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.

Deauthenticating will delete locally stored data (which includes the user’s conversations and messages).

You can deauthenticate at any point in your app:

[self.layerClient deauthenticateWithCompletion:^(BOOL success, NSError *error) {
    if (!success) {
        NSLog(@"Failed to deauthenticate user: %@", error);
    } else {
        NSLog(@"User was deauthenticated");
    }
}];

Note

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

Connecting Identities