Token auth

Token authentication uses a trusted device with an API key to issue time-limited tokens to untrusted clients. Tokens have a limited set of access rights, known as capabilities, and can have a specific identity using a clientId.

Token authentication is the recommended authentication method to use client-side as it provides more fine-grained access control and limits the risk of credentials being exposed.

Any of the following cause an SDK to use token authentication:

Providing a literal token or tokenDetails is typically used for testing: since tokens are short-lived, in production you typically want to use an authentication method that allows the client library to renew the token automatically before the current token expires.

Authentication using tokens can be achieved requesting and issuing Ably Tokens or passing a JSON Web Tokens (JWT) to the Ably service.

One of the important benefits of using an Ably SDK is that the automatic refresh of tokens will be handled for you.

To use automatic refresh of tokens, provide either an authUrl or an authCallback. When the token is near to expiry the authUrl or authCallback is invoked and a new token is automatically requested.

An authURL is recommended for use with web-based clients as they can easily utilize cookies and other web-only features. For non-web clients, authCallback is the recommended strategy.

You can specify an authUrl when you create the Ably client. For example:

Select...
const realtime = new Ably.Realtime({ authUrl: '/auth' });
Copied!

The client will obtain a token, JWT, or tokenRequest from the URL and use it to authenticate requests to Ably. Before token expiry, a request for a new token will be made automatically by the client to the authUrl.

You can specify an authentication callback function when you create the Ably client. Inside authCallback, you can make a network request to your servers to generate the tokenRequest. For example:

Select...
const ablyClient = new Realtime({ authCallback: async (tokenParams, callback) => { try { const tokenRequest = await createTokenRequest() // Make a network request to your server callback(null, tokenRequest) } catch (error) { callback(error, null) } } });
Copied!

The tokenParams argument in authCallback is available for convenience, allowing you to see the capabilities, clientId, and other details requested by the client. However, tokenParams should not be trusted or used to generate the tokenRequest on the server side. Instead it is recommended that your createTokenRequest API authenticates clients separately, for example based on cookies, headers, or HTTP body.

Use properties set with AuthOptions to override the default authentication values set when instantiating a client. You can also embed AuthOptions into your ClientOptions while instantiating.

There are several AuthOptions you can specify along with authUrl and authCallback:

  • authMethod :- when authUrl is called, the default GET method will be used, unless POST is specified.
  • authHeaders :- allows you to pass additional headers as required, depending on your use case.
  • authParams :- allows you to pass additional query parameters, depending on your use case.

The following is an example of passing AuthOptions:

Select...
const realtime = new Ably.Realtime({ authUrl: "/auth", authMethod: "POST", authParams: { p1: param1, b: param2}, authHeaders: {h1: header1, h2: header2} });
Copied!

Ably Tokens can be used to authenticate with Ably in the following ways:

  • Ably TokenRequest is created by your servers and passed to clients.
  • An Ably Token is issued by your servers and passed to clients.

Note that the machine on which you are running your auth server should have an accurate clock, as tokens and TokenRequest contain a timestamp. You can use an NTP daemon, or if you are not able to control your server’s clock, you can wish to use the queryTime auth option.

Using an Ably SDK, a TokenRequest is generated from your server and returned to the client-side SDK instance. The client-side SDK instance then uses the TokenRequest to request an Ably Token from Ably, and subsequently authenticates using that Ably Token.

This is the recommended approach for client-side authentication, for the following reasons:

  • An Ably TokenRequest can be generated securely by your servers without communicating with Ably.
  • Your secret API key is never shared with Ably or your clients.
  • An Ably TokenRequest cannot be tampered with due to being signed, must be used soon after creation, and can only be used once.

The process used by Ably SDKs to authenticate with Ably using a TokenRequest is illustrated in the following diagram:

Ably TokenRequest auth process diagram

The following is an example of creating an Ably TokenRequest:

Select...
const ably = new Ably.Rest({ key: '<loading API key, please wait>' }); const tokenRequest = await ably.auth.createTokenRequest({ clientId: '[email protected]' });
Demo Only
Copied!

Clients can pass this server-side generated TokenRequest to Ably to authenticate with Ably automatically.

Using an Ably SDK, an Ably Token is requested by your servers from Ably and then passed to the client-side SDK instance. The client-side SDK instance then uses that Ably Token to authenticate with Ably. This is an alternative approach for authentication that enables you to issue“Ably Tokens directly as opposed to providing Ably TokenRequests from your servers.

The advantage for clients is that it saves one round trip request as they do not need to request an Ably Token themselves. The disadvantage is that your servers must communicate with Ably each time an Ably Token is required.

The process used by Ably SDKs to authenticate with Ably using an Ably Token is illustrated in the following diagram:

Ably token auth process diagram

The following is an example of issuing an Ably Token from a server:

Select...
const ably = new Ably.Rest({ key: '<loading API key, please wait>' }); const tokenDetails = await ably.auth.requestToken({ clientId: '[email protected]' });
Demo Only
Copied!

JSON Web Tokens (JWT) can be used to authenticate with Ably in the following ways:

  • Ably JWT is created by your servers and passed to clients.
  • Ably Token is embedded in a JWT from your server and passed to clients.

Note that the machine on which you are running your auth server should have an accurate clock, as tokens contain a timestamp. You can use an NTP daemon, or if you are not able to control your server’s clock, you can wish to use the queryTime auth option.

It is possible to use a JWT as a form of token for authentication with Ably, so long as it is structured appropriately, in what will be referred to as an Ably JWT. It is possible for an Ably JWT to contain claims indicating its clientId, capabilities and expiry – in an analogous way to an Ably Token – and it is signed with the applicable Ably API key’s secret part.

This is similar to signing an Ably TokenRequest, but the client does not need to request an Ably Token, instead being able to use the Ably JWT as a token in itself. Any compliant third-party JWT library may be used to create the JWT without requiring the token to be issued by Ably. This can be useful for situations where an Ably client library is not available, such as an embedded device connecting to Ably via MQTT.

The process used by Ably SDKs to authenticate with Ably using JWTs is illustrated in the following diagram:

Ably JWT auth method

The following is an example of creating an Ably JWT:

Select...
var header = { "typ":"JWT", "alg":"HS256", "kid": "{{API_KEY_NAME}}" } var currentTime = Math.round(Date.now()/1000); var claims = { "iat": currentTime, /* current time in seconds */ "exp": currentTime + 3600, /* time of expiration in seconds */ "x-ably-capability": "{\"*\":[\"*\"]}" } var base64Header = btoa(header); var base64Claims = btoa(claims); /* Apply the hash specified in the header */ var signature = hash((base64Header + "." + base64Claims), "{{API_KEY_SECRET}}"); var ablyJwt = base64Header + "." + base64Claims + "." + signature;
Copied!

At present Ably does not support asymmetric signatures based on a key pair belonging to a third party.

If a system has an existing JWT scheme, it’s possible to embed an Ably Token as a claim within it.

The JWT and embedded token need to meet the following requirements:

  • The embedded token is an Ably Token.
  • The embedded token is included under the x-ably-token key in the JOSE Header, or if using JWS, the embedded token is included using the x-ably-token claim in the payload.
  • The expiry time of the embedded token must not be earlier than the outer JWT‘s expiry time (exp claim). Ably will reject any JWT if it is unencrypted and its exp claim is later than the expiry of the enclosed token. This helps to ensure that tokens are renewed prior to expiry.

The process used by Ably SDKs to authenticate with Ably using an Ably Token embedded in a JWT is illustrated in the following diagram:

Token embedded in a JWT auth method

The following is an example of issuing an Ably Token inside the of header of a JWT. Note that the authenticity of the JWT will not be checked, due to Ably not having access to your SECRET key.

Select...
const ably = new Ably.Rest({ key: '<loading API key, please wait>' }); const tokenDetails = await ably.auth.requestToken({ clientId: '[email protected]' }); const header = { "typ":"JWT", "alg":"HS256", "x-ably-token": tokenDetails.token } const claims = { "exp": currentTime + 3600 } const base64Header = btoa(header); const base64Claims = btoa(claims); /* Apply the hash specified in the header */ const signature = hash((base64Header + "." + base64Claims), SECRET); const jwt = base64Header + "." + base64Claims + "." + signature; /* Send jwt to client */
Demo Only
Copied!

Ably recommends that token authentication is used client-side for the following reasons:

  • Tokens ensure that an Ably API key isn’t exposed in client applications.
  • Tokens are short-lived so there is only a short period of time during which a compromised token can be used.
  • Tokens provide more fine-grained access control, which also limits the area of exposure a compromised token can access.

Token refresh
v2.0