Authentication endpoints

Introduction

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.

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 or identifiers at some other point, the entire flow can occur in the background without any user intervention.

Example

This example uses some pseudo code to simplify. See endpoint

/*
 * 1. Get a nonce
 */
function getNonce() {
  xhr({
    method: "POST",
    url: "https://api.layer.com/nonces",
    headers: {
      "accept": "application/vnd.layer+json; version=3.0",
      "Content-Type": "application/json"
    },
    onSuccess: function(data) {
      getIdentityToken(data.nonce);
    }
  });
}

/*
 * 2. On receiving a nonce,
 *    Connect to your backend to generate an Identity Token (see below). 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 or your own server's Session Tokens).
 */
function getIdentityToken(nonce) {
  xhr({
    url: 'https://myservice.com/identity',
    method: 'POST',
    data: {
        nonce: nonce
    },
    onSuccess: function(data) {
      getSessionToken(data.identity_token);
    }
  });
}

/*
 * 3. On receiving an Identity Token from your server, get a Session Token from Layer's Server.
 */
function getSessionToken(identityToken) {
  xhr({
    method: "POST",
    url: "https://api.layer.com/sessions",
    headers: {
      "accept": "application/vnd.layer+json; version=3.0",
      "Content-Type": "application/json"
    },
    data: {
      identity_token: identityToken,
      app_id: "layer:///app/staging/MY_APP_UUID"
    },
    onSuccess: function(data) {
      alert("Your Session Token is " + data.session_token);
    }
  });
}

At the end of this process, you have a Session Token that can be used to make authenticated requests to Layer’s services.

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.

Endpoints

Method HTTP request Description
Request nonce POST /nonces Obtain a nonce to begin the authentication flow
Request session token POST /sessions Get a session token, used to authenticate future requests
Delete session token DELETE /sessions/:token Logs out clients using the token

Request nonce

The client requests a nonce to begin the authentication flow. Nonces expire 10 minutes after they are requested.

Note

This method does not require authorization.

Parameters:

This method takes no parameters.

HTTP request:

POST/nonces

Example:

curl -X POST \
     -H 'Accept: application/vnd.layer+json; version=3.0' \
     -H 'Content-Type: application/json' \
     https://api.layer.com/nonces

Possible responses:

Nonce obtained | Status: 201 (Created)

{
    "nonce": "b7a5fba5ad402d072013c1949481c1080860ff32"
}

Request session token

Once you have your identity token, you can request a session token.

Note

This method does not require authorization.

Parameters:

Name Type Description
identity_token string Token validating your identity
app_id string Your Layer app ID

HTTP request:

POST/sessions

Example:

{
    "identity_token": "f6179ecb285c669c07415011f17d7a4e59ce1f91.9afd0f5ef6df7bf7eb13e9ada65fa28cf765a51c.450b81833898cb159f3cfc5a9a839187e63683e0",
    "app_id": "layer:///apps/production/e49e50aa-ffda-453f-adc8-404f68de84ae"
}
curl -X POST \
     -H 'Accept: application/vnd.layer+json; version=3.0' \
     -H 'Content-Type: application/json' \
     https://api.layer.com/sessions\
 -d '{"identity_token":"f6179ecb285c669c07415011f17d7a4e59ce1f91.9afd0f5ef6df7bf7eb13e9ada65fa28cf765a51c.450b81833898cb159f3cfc5a9a839187e63683e0","app_id":"layer:///apps/production/e49e50aa-ffda-453f-adc8-404f68de84ae"}'

Possible responses:

Session token obtained | Status: 201 (Created)

{
    "session_token": "c3ba507fc4fc3c8e0618c4bee3250132e86bd7e9"
}

Invalid app ID | Status: 403 (Forbidden)

{
    "id": "invalid_app_id",
    "code": 2,
    "message": "The client provided an invalid Layer App ID",
    "url": "https://developer.layer.com/reference/api#authentication"
}

Invalid identity token | Status: 422 (undefined)

{
    "id": "invalid_property",
    "code": 105,
    "message": "Invalid identity token; go to the developer dashboard's authentication tab and use the identity token validation form for more details.",
    "url": "https://developer.layer.com/",
    "data": {
        "property": "identity_token"
    }
}

Discussion

A successful response also includes URLs in the Link header. It is important to use these URLs rather than trying to construct your own.

Link: <https://api.layer.com/conversations>; rel=conversations,
  <https://api.layer.com/content>; rel=content,
  <https://api.layer.com/websocket>; rel=websocket

Possible rel values:

  • conversations: URL to get the first page of conversations
  • content: URL for uploading content such as photos or videos
  • websocket: URL for establishing a WebSocket connection

Errors:

A number of errors are possible when requesting a Session Token:

Error message Description
eit_claim_not_found Invalid claim. Missing fields.
eit_claim_wrong_type Invalid claim. Wrong value type specified.
eit_expired Token expired. Check your expiration timestamp found in the exp field.
eit_header_param_not_found Invalid header. Missing parameters
eit_header_param_wrong_type Invalid header. Wrong type
eit_header_param_wrong_value Invalid header. Should be set to JWT
eit_key_deleted The Key ID you specified has been deleted. Please use a different key or create a new one.
eit_key_disabled The Key ID you specified has been disabled. Please use a different key or create a new one.
eit_key_malformed The Key ID you specified is invalid
eit_key_not_found Authentication Key in the kid field is invalid. Make sure you provide a valid Authentication Key (Should start with layer:///keys/…)
eit_malformed_base64url Invalid identity token structure. Should be base64-URL-encoded.
eit_malformed_json Invalid identity token structure. Please refer to our documentation on how to create a valid token.
eit_nonce_not_found Nonce not found or has expired
eit_not_before This identity token can not be used before the iat timestamp.
eit_provider_not_bound_to_app This Provider ID found in the iss field is not bound to a valid application.
eit_provider_not_found A valid Provider ID should be set in the iss field.
eit_signature_verification_failed Signature verification failed. This usually means that the token was signed by a different private key which does not match the Authentication Key ID provided in the kid field.
eit_user_suspended Provided User ID found in the prn field has been blacklisted.
eit_wrong_jws_part_count Invalid identity token structure. Please refer to our documentation on how to create a valid token.

Delete session token

Parameters:

Name Type Description
token string Your session token

HTTP request:

DELETE/sessions/:token

Example:

{
    "token": "7Rti7Cl6m3JA4GdjXRcnyBvovv0q-DBHpQdmGUZblKJbGzODoAYW7Z5o_a5bJjqkD_CU_pe9qr11111111111.1-1"
}
curl -X DELETE \
     -H 'Accept: application/vnd.layer+json; version=3.0' \
     -H 'Authorization: Layer session-token="<TOKEN>"'' \
     -H 'Content-Type: application/json' \
     https://api.layer.com/sessions/7Rti7Cl6m3JA4GdjXRcnyBvovv0q-DBHpQdmGUZblKJbGzODoAYW7Z5o_a5bJjqkD_CU_pe9qr11111111111.1-1

Possible responses:

Session token deleted
Status: 204 (No Content)
(Empty body)