Authentication

Both the REST client library and the Realtime client library use common authentication mechanisms. The two schemes supported by Ably are Basic Authentication, which uses your private API key, and Token Authentication, which uses short-lived tokens for access which are periodically renewed.

Token Authentication, in most cases, is the recommended strategy on the client-side as it provides more fine-grained access control and limits the risk of exposed or compromised credentials.

Tutorials & Examples

If you would like to just dive in and see an example of Ably authentication in code, then take a look at our client-server authentication tutorials.

Basic Authentication

Every application has one or more private API keys that you set up and configure via the dashboard. These keys can be used to authenticate with Ably. It is recommended that private API keys are never shared with untrusted parties, and as such, should only be used by your trusted secure servers when authenticating with Ably.

Basic authentication is the simplest way to authenticate with Ably. It is as simple as:

var ably = new Ably.Realtime({ key: 'xVLyHw.W4gTFw:VYz7z5jEvf_oIMqu' });

Process used by client libraries connecting with basic auth:


Basic authentication process diagram

Whilst Basic Authentication is simple, we recommend it to be only used on the server-side as it suffers from a number of problems:

  • the secret is passed directly by the client to Ably, so it is not permitted for connections that are not over TLS (HTTPS or non-encrypted realtime connections) to prevent the key secret being intercepted
  • all of the configured capabilities of the key are implicitly possible in any request, and clients that legitimately obtain this key may then abuse the rights for that key
  • clients are permitted to use any client ID in all operations with Ably. As such, a client ID in messages and presence cannot be trusted as any client using Basic Authentication can masquerade with any client ID

Token Authentication

Client-side devices should generally be considered untrusted, and as such, it is important that you minimize the impact of any credentials being compromised on those devices. Token authentication achieves this by having a trusted device, such as one of your own servers, posessing an API key configured via the dashboard. It can then use the API key to distribute time-limited tokens with limited sets of access rights or capabilities, or with specific identities to untrusted clients.

Different token-issuing mechanisms can be used with Ably; the default is to use Ably Tokens which you request from Ably based on an Ably TokenRequest that you sign and issue from your servers to clients; or a JSON Web Token (JWT) which you generate on your servers and sign using your private API key. Token Authentication, in most cases, is the recommended strategy on the client-side as it provides more fine-grained access control and limits the risk of exposed or compromised credentials.

In order to instantiate a client library with token authentication, one of the following options should be used:

Token authentication is typically done in one of four ways:

Ably TokenRequest is created by your servers and passed to clients

Using our REST or Realtime client libraries, an Ably TokenRequest is generated from your servers and handed to the client-side client library. The client-side client library then uses that Ably TokenRequest to request an Ably Token from Ably and subsequently authenticate using that Ably Token. This is the recommended approach for authentication as: 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. Ably TokenRequests cannot be tampered with due to being signed, must be used soon after creation and can only be used once.

var ably = new Ably.Rest({ key: 'xVLyHw.W4gTFw:VYz7z5jEvf_oIMqu' });
ably.auth.createTokenRequest({ clientId: 'client@example.com' }, null, function(err, tokenRequest) {
  /* tokenRequest => {
       "capability": "{\"*\":[\"*\"]}",
       "clientId": "client@example.com",
       "keyName": "xVLyHw.W4gTFw",
       "nonce": "5576521221082658",
       "timestamp": _VAR_MS_SINCE_EPOCH_VAR_,
       "mac": "GZRgXssZDCegRV....EXAMPLE"
     } */
});


Ably TokenRequest auth process diagram

Ably Token is issued by your servers and passed to clients

Using our REST or Realtime client libraries, an Ably Token is requested by your servers from Ably and then handed to the client-side client library. The client-side client library then uses that Ably Token to authenticate with Ably. This is an alternative approach for authentication that allows you to issue Ably Tokens directly as opposed to providing Ably TokenRequests from your servers. The advantage for clients is 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.

var ably = new Ably.Rest({ key: 'xVLyHw.W4gTFw:VYz7z5jEvf_oIMqu' });
ably.requestToken({ clientId: 'client@example.com' }, function(err, token) {
  /* token => {
       "token": "xVLyHw.Dtxd9tuz....EXAMPLE",
       "capability": "{\"*\":[\"*\"]}"
       "clientId": "client@example.com",
       "expires": 1449745287315,
       "keyName": "xVLyHw.W4gTFw",
       "issued": 1449741687315,
     } */
});


Ably Token auth process diagram

Ably JWT is created by your servers and passed to clients

In most scenarios, we would recommend you use one of the many JWT libraries available when constructing your JWT.

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 an applicable Ably API key.

This is similar to signing an Ably TokenRequest, but the client does not need then 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.

var header = { 
    "typ":"JWT",
    "alg":"HS256",
    "kid": "xVLyHw.W4gTFw"
  }
  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), SECRET);
  var ablyJwt = base64Header + "." + base64Claims + "." + signature;

Note: At present Ably does not support asymmetric signatures based on a keypair belonging to a third party. If this is something you’d be interested in, please get in touch.


Ably JWT auth method

Ably-compatible token is embedded in a External JWT from your server and passed to clients

If a system has an existing JWT scheme, it can be useful to embed an Ably-compatible token as a claim within it. The External JWT and embedded Ably-compatible token need to meet the following requirements:

  • The embedded token is an Ably JWT, or 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
var ably = new Ably.Rest({ key: 'xVLyHw.W4gTFw:VYz7z5jEvf_oIMqu' });
ably.auth.requestToken({ clientId: 'client@example.com' }, function(err, tokenDetails) {
  var header = { 
    "typ":"JWT",
    "alg":"HS256",
    "x-ably-token": tokenDetails.token
  }
  var claims = {
    "exp": currentTime + 3600
  }
  var base64Header = btoa(header);
  var base64Claims = btoa(claims);
  /* Apply the hash specified in the header */
  var signature = hash((base64Header + "." + base64Claims), SECRET);
  var jwt = base64Header + "." + base64Claims + "." + signature;
  /* Send jwt to client */
});

Note: The authenticity of the JWT will not be checked, due to Ably not having access to your SECRET key.


Token embedded in a JWT auth method

Selecting an authentication mechanism

When deciding on which authentication method you will be using, it is recommended to bear in mind the principle of least privilege: a client should ideally only possess the credentials and rights that it needs to accomplish what it wants; this way, if the credentials are compromised, the rights that can be abused by an attacker are minimized.

The table below should be used as a rough guide as to what you should consider when choosing your authentication method. Many applications will most naturally use a mixed strategy: one or more trusted application servers will use basic authentication to access the service and issue tokens over HTTPS, whereas remote browsers and devices will use individually issued tokens.:

Scenario Basic Token Description
Your scripts may be exposed No Yes If the script, program or system holding the key is exposed, for example on a user’s device, you should not embed an API key and instead use Token Authentication. If the script is on a secure environment such as your own server, an API key with Basic Authentication is fine.
Your connection may be insecure No Yes If there is a risk of exposure of the client’s credentials, either directly or over an insecure, or insecurely proxied, connection, Token Authentication should be used. If you are sure the connection is secure and unmediated, Basic Authentication is acceptable.
You have no server to control access Yes No If you do not have your own server to perform authentication and provide tokens to users, you’ll need to use Basic Authentication.
You require fine-grained access control No Yes If you need to provide privileges on a user-by-user basis, you’d be better using Token Authentication. If you only need a few access control groups, Basic Authentication is reasonable.
Users need restricted periods of access No Yes If you need users to only have access for a certain period of time, or the ability to revoke access, Token Authentication is needed. If users are able to always have access, Basic Authentication is acceptable.
Users need to identify themselves Partial Yes If the user can be trusted to identify itself, Basic Authentication is fine. If the user cannot be trusted however, Token Authentication is better as it allows for a trusted token distributor to identify the user instead.

Capabilities and Token Security explained

API keys, like Ably-compatible tokens, have a set of capabilities assigned to them that specify which operations (such as subscribe or publish) can be performed on which channels. However, unlike tokens, API keys are long-lived, secret and typically not shared with un-trusted clients.

API keys and their capabilities are configured using the dashboard, they cannot be added or removed programmatically. Ably-compatible tokens on the other hand are designed to be shared with un-trusted clients, are short-lived, and significantly, they are configured and issued programmatically. See selecting an authentication scheme to understand why token authentication, in most cases, is the preferred authentication scheme.

Ably Tokens are issued from an existing API key, and their capabilities can, at most, match the capabilities of the issuing API key. Ably JWTs have a similar restriction on capabilities, correlating to the API key they’ve been signed with. If an API key must be shared with a third party, then it is recommended that the principle of least privilege is considered, assigning only the capabilities needed by that third party. Thus, any Ably requests authenticated using that API key or Ably-compatible tokens associated with that API key, will be restricted to the capabilities assigned to the API key.

  • If no capability is specified in the Ably TokenRequest, then the Ably Token will be given the full set of capabilities assigned to the issuing key; see example.
  • If a set of capabilities are requested, then the Ably Token will be assigned the intersection of the requested capability and the capability of the issuing key, see example.
  • If a set of capabilities are requested, and the intersection between those and the API key’s capabilities is empty (ie they are entirely incompatible), then the Ably Token request will result in an error, see example.
  • The capabilities granted to an Ably JWT will be the intersection of the capabilities within the Ably JWT with the capabilities of the associated API key;
  • If the set of capabilities within the Ably JWT have no intersection with the capabilities of the API key, then an error will instead be returned, see example.

See capability operations below for the complete set of supported operations on a channel.

Resource names and wildcards

Capabilities are a map from resources to a list of operations. Each resource can match a single channel e.g. channel, or multiple channels using wildcards (*). Wildcards can only replace whole segments (segments are delimited by :) of the resource name. A wildcard at the end of the name can replace arbitrarily many segments. For example:

  • A resource of * will match any channel
  • A resource of namespace:* will match any channel in the namespace namespace, including namespace:channel, and namespace:channel:other
  • A resource of foo:*:baz will match foo:bar:baz, but not foo:bar:bam:baz
  • A resource of foo:* will match foo:bar, foo:bar:bam, foo:bar:bam:baz etc., as the wildcard as at the end
  • A resource of foo* (without a colon!) will only match the single channel literally called foo*, which probably isn’t what you want

A resource can also be a queue, in which case it will start with [queue], e.g. [queue]appid-queuename. (This is unambiguous as channel names may not begin with a [). Similar wildcard rules apply, e.g. [queue]* will match all queues.

You can also have a resource name of [*]*, which will match both all queues and all channels.

Wildcards are also supported for operations, by requesting an operations list of ['*'].

Capabilities example in code

If you want to see some live code examples of how capabilities work, take a look at our capabilities example.

Ably Token request without capabilities example

Given an API key exists with the following capabilities:

{
  "chat": ["publish", "subscribe", "presence"],
  "status": ["subscribe"]
}

If an Ably Token is requested without requiring any capabilities:

auth.requestToken(tokenCallback)

Then the request for an Ably Token is treated as requesting all capabilities, i.e. {"[*]*":["*"]}), and all capabilities of the API key are assigned to the Ably Token. The capabilities for the issued Ably Token would be as follows:

{
  "chat": ["publish", "subscribe", "presence"],
  "status": ["subscribe"]
}

Ably Token is requested with intersection of capabilities example

Given an API key exists with the following capabilities:

{
  "chat:*": ["publish", "subscribe", "presence"],
  "status": ["subscribe", "history"],
  "alerts": ["subscribe"]
}

And an Ably Token is requested with the following explicit capabilities:

auth.requestToken({ capability: {
  "chat:bob": ["subscribe"], // only "subscribe" intersects
  "status": ["*"], // "*"" intersects with "subscribe"
  "secret": ["publish", "subscribe"] // key does not have access to "secret" channel
}}, tokenCallback)

Then Ably will intersect the API key’s capabilities and the requested capabilities ie Ably will satisfy the requested Ably Token’s capabilities as far as possible based on the capability of the issuing API key. The capabilities for the issued Ably Token would be as follows:

{
  "chat:bob": ["subscribe"],
  "status": ["subscribe", "history"]
}

Ably Token is requested with incompatible capabilities

Given an API key exists with the following capabilities:

{
  "chat": ["*"]
}

And an Ably Token is requested with the following explicit capabilities:

auth.requestToken({ capability: {
  "status": ["*"]
}}, tokenCallback)

Then Ably will be unable to issue an Ably Token because the intersection of the requested capabilities and the API key’s capabilities is empty – they are entirely incompatible. In the example above, requestToken will call the callback with an error.

See a working capabilities example.

Capability operations

The following capability operations are available for API keys and issued tokens.

subscribe
can subscribe to messages and presence state change messages on channels, and get the presence set of a channel
publish
can publish messages to channels
presence
can register presence on a channel (enter, update and leave)
history
can retrieve message and presence state history on channels
stats
can retrieve current and historical usage statistics for an app
push-subscribe
can subscribe devices for push notifications
push-admin
can manage device registrations and push subscriptions for all devices in an app

See a working capabilities example, read understanding capabilities and token security above to get a more thorough overview of how capabilities can be used to secure your application along with working examples.

Understanding Identified clients

When a client is authenticated and connected to Ably, they are considered to be an authenticated client. However, whilst an authenticated client has a verifiable means to authenticate with Ably, they do not necessarily have an identity. When a client is assigned a trusted identity (ie a client ID), then they are considered to be an identified client and for all operations they perform with the Ably service, their client ID field will be automatically populated and can be trusted by other clients.

For example, assuming you were building a chat application and wanted to allow clients to publish messages and be present on a channel. If each client is assigned a trusted identity by your server, such as a unique email address or UUID, then all other subscribed clients can trust any messages or presence events they receive in the channel as being from that client. No other clients are permitted to assume a client ID that they are not assigned in their Ably-compatible token, that is they are unable to masquerade as another client ID.

In Ably a client can be identified with a client ID in two ways:

  • if the client is authenticated with an Ably-compatible token that is issued for that client ID;
  • if the client claims that client ID (as part of ClientOptions in the constructor) and is authenticated with an Ably-compatible token that is issued for a wildcard client ID (a special token privilege that allows any client identity to be assumed)

We encourage customers to always issue Ably-compatible tokens to clients so that they authenticate using the short-lived token and do not have access to a customer’s private API keys. Since the customer can then control the client ID that may be used by any of its clients, all other clients can rely on the validity of the client ID in published messages and of members present in presence channels.

The following Javascript example demonstrates how to issue an Ably Token with an explicit client ID that, when used by a client, will then be considered an identified client.

var realtime = new Ably.Rest({ key: 'xVLyHw.W4gTFw:VYz7z5jEvf_oIMqu' });
realtime.auth.createTokenRequest({ clientId: 'Bob' }, function(err, tokenRequest) {
  /* ... issue the TokenRequest to a client ... */
})

Token Types

In the documentation, references to Ably-compatible tokens typically refer either to an Ably Token, or an Ably JWT. For Ably Tokens, this can either be referring to the TokenDetails object that contain the token string or the token string itself. TokenDetails objects are obtained when requesting an Ably Token from the Ably service and contain not only the token string in the token attribute, but also contain attributes describing the properties of the Ably Token. For Ably JWT, this will be simply referring to a JWT which has been signed by an Ably private API key.

TokenDetails type

TokenDetails is a type providing details of Ably Token string and its associated metadata.

PropertiesMembersAttributes

tokenToken
The Ably Token itself. A typical Ably Token string may appear like xVLyHw.AvtQgVw2Z9HcXzvq1Bdy55IhK4QpYc_sckM46ym63DcbS3WVMU
Type: String
expiresExpires
The time (in milliseconds since the epoch)The time at which this token expires
Type: IntegerLong IntegerDateTimeOffsetTimeNSDate
issuedIssued
The time (in milliseconds since the epoch)The time at which this token was issued
Type: IntegerLong IntegerDateTimeOffsetTimeNSDate
capabilityCapability
The capability associated with this Ably Token. The capability is a a JSON stringified canonicalized representation of the resource paths and associated operations. Read more about authentication and capabilities
Type: StringCapability
clientIdclient_idClientId
The client ID, if any, bound to this Ably Token. If a client ID is included, then the Ably Token authenticates its bearer as that client ID, and the Ably Token may only be used to perform operations on behalf of that client ID. The client is then considered to be an identified client
Type: String

Methods

expired?
True when the token has expired
Type: Boolean

Methods

is_expired()
True when the token has expired
Type: Boolean

Methods

IsValidToken()
True if the token has not expired
Type: Boolean

TokenDetails constructors

TokenDetails.fromJsonTokenDetails.from_json

TokenDetails.fromJson(String json) → TokenDetailsTokenDetails.from_json(String json) → TokenDetails

TokenDetails.fromJson(Object json) → TokenDetailsTokenDetails.from_json(Object json) → TokenDetails

A static factory method to create a TokenDetails from a deserialized TokenDetails-like object or a JSON stringified TokenDetails. This method is provided to minimize bugs as a result of differing types by platform for fields such as timestamp or ttl. For example, in Ruby ttl in the TokenDetails object is exposed in seconds as that is idiomatic for the language, yet when serialized to JSON using to_json it is automatically converted to the Ably standard which is milliseconds. By using the fromJson method when constructing a TokenDetails, Ably ensures that all fields are consistently serialized and deserialized across platforms.

Parameters

json
a TokenDetails-like deserialized object or JSON stringified TokenDetails.
Type: Object, String

Returns

A TokenDetails object

Ably JWT

An Ably JWT is not strictly an Ably construct, rather it is a JWT which has been constructed to be compatible with Ably. The JWT must adhere to the following to ensure compatibility:

  • The JOSE header must include:
    • kid – Key name, such that an API key of xVLyHw.W4gTFw:VYz7z5jEvf_oIMqu will have key name xVLyHw.W4gTFw
  • The JWT claim set must include:
    • iat – time of issue in seconds
    • exp – expiry time in seconds
  • The JWT claim set may include:
    • x-ably-capabilityJSON text encoding of the capability
    • x-ably-clientId – client ID

Arbitrary additional claims and headers are supported (apart from those prefixed with x-ably- which are reserved for future use).

The Ably JWT must be signed with an Ably API key using one of the following signature algorithms (as defined in JWA):

  • HS256HMAC using the SHA-256 hash algorithm
  • HS384HMAC using the SHA-384 hash algorithm

We recommend you use one of the many JWT libraries available for simplicity when creating your JWTs.

Auth object

The principal use-case for the Auth object is to create Ably TokenRequest objects with createTokenRequest or obtain Ably Tokens from Ably with requestToken, and then issue them to other “less trusted” clients. Typically, your servers should be the only devices to have a private API key, and this private API key is used to securely sign Ably TokenRequest objects or request Ably Tokens from Ably. Clients are then issued with these short-lived Ably Tokens or Ably TokenRequest objects, and the libraries can then use these to authenticate with Ably. If you adopt this model, your private API key is never shared with clients directly.

A subsidiary use-case for the Auth object is to preemptively trigger renewal of a token or to acquire a new token with a revised set of capabilities by explicitly calling authorizeAuthorize.

Descriptions of this object exist in both the Realtime and REST libraries.


Get started now with our free plan

It includes 3m messages per month, 100 peak connections, 100 peak channels, and loads of features.

Create your free account