Capabilities

Open in

API keys and 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.

API keys are long-lived, secret and typically not shared with clients. API key capabilities are configured using the dashboard, or using the Control API.

Ably-compatible tokens are designed to be shared with untrusted clients, are short-lived, and can be configured and issued programmatically. For restricting client access to channels, tokens provide far more flexibility and security than API key capabilities. See selecting an authentication mechanism to understand why token authentication is the preferred option in most scenarios.

Capability changes and existing connections

Once created, it's best to think of keys and tokens as being immutable. To modify the permissions granted to existing connections, the recommended approach is to use token authentication and issue the client a new token with the updated permissions you want them to have.

The one exception is if a key is revoked entirely, in which case all connections using that key (or a token derived from that key) will be forcibly terminated. See token revocation for more information.

Resource names and wildcards

Capabilities are a map from resources to a list of operations. Each resource can match a single channel, for example, 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 arbitrarily replace many segments. For example:

  • A resource of * will match any channel, but not queues and metachannels.
  • 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 expressions such as foo:bar, foo:bar:bam, foo:bar:bam:baz, as the wildcard is at the end.
  • A resource of foo* (without a colon) will only match the single channel literally called foo*.

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

A resource can also be a metachannel, in which case it will start with [meta], for example [meta]metaname. This is unambiguous as channel names may not begin with a [. [meta]* will match all metachannels. Just * on its own will not: it will match all possible normal channels, but no metachannels.

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

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

Capability operations

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

OperationDescription
subscribeCan subscribe to messages, objects, and presence state change messages on channels, and get the presence set of a channel
publishCan publish messages to channels
presenceCan register presence on a channel (enter, update and leave)
object-subscribeCan subscribe to updates to objects on a channel
object-publishCan update objects on a channel
annotation-subscribeCan subscribe to individual annotations on a channel
annotation-publishCan publish annotations to messages on a channel
message-update-ownCan update messages where the original publisher's clientId matches the updater's clientId
message-update-anyCan update any message on the channel
message-delete-ownCan delete messages where the original publisher's clientId matches the deleter's clientId
message-delete-anyCan delete any message on the channel
historyCan retrieve message and presence state history on channels
statsCan retrieve current and historical usage statistics for an app
push-subscribeCan subscribe devices for push notifications
push-adminCan manage device registrations and push subscriptions for all devices in an app
channel-metadataCan get metadata for a channel, and enumerate channels
privileged-headersCan set data in the privileged section of the message extras

Although most capabilities need to be enabled for the resource you're using them with, there are exceptions. The stats permission only does something when attached to the wildcard resource '*', or a resource that contains that as a subset, such as '[*]*', since stats are app-wide.

Channel access control

Ably does not provide numeric limits on channel access. Control channel access using token authentication and capabilities.

Channel access is controlled through:

  • Token authentication to restrict access by issuing tokens with specific capabilities to authorized users.
  • Specific clientId values in tokens to ensure only certain users can access particular channels.
  • Granting or restricting specific operations (subscribe, publish, presence) on channels through capability configurations.

For private messaging or group chats, design channel naming strategies and use token authentication to ensure users receive tokens with access only to relevant channels.

The channel-metadata permission works both ways. When associated with a specific channel or set of channels it allows you to query the metadata of a channel to request its status. When associated with the wildcard resource '*' it takes on an additional meaning: as well as allowing channel status requests for all channels, it also allows you to enumerate all active channels.

API key capabilities

An Ably API key can have a single set of permissions, applied to any number of channels or queues.

You can also choose whether to restrict the API key to only channels, only queues, or to match a set of channel or queue names. If you've chosen to restrict the API key to selected channels and queues, you can use a comma separated list of resources the API key can access, making use of wildcards to provide access to areas of your app. It is worth noting an API key will provide the same permissions to all resources it has access to.

To view the capabilities for an existing API key:

  1. Sign into your Ably dashboard.
  2. Select the API Keys tab.
  3. Click the Settings button for the key you want to check the capabilities for.

Token capabilities

Ably Tokens and JWTs are issued from an existing API key and their capabilities can, at most, match the capabilities of the issuing API key.

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.

JWTs are the recommended approach for setting token capabilities. Use a TokenRequest as an alternative when your capability list is very large or must remain confidential.

Using JWT

Set capabilities in a JWT using the x-ably-capability claim. No Ably SDK is required:

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

// Server-side: Create JWT with capabilities using any JWT library
import jwt from 'jsonwebtoken';

const [keyName, keySecret] = process.env.ABLY_API_KEY.split(':');

const ablyJwt = jwt.sign(
  {
    'x-ably-capability': JSON.stringify({
      'your-namespace:*': ['publish', 'subscribe', 'presence'],
      'notifications': ['subscribe'],
    }),
    'x-ably-clientId': userId,
  },
  keySecret,
  { algorithm: 'HS256', keyid: keyName, expiresIn: '1h' }
);

Using TokenRequest

Use a TokenRequest when your capability list is very large (JWTs must fit within HTTP header limits, typically around 8 KB) or when capabilities need to be kept confidential (JWTs can be decoded by clients):

1

2

3

4

5

6

7

8

// Server-side with Ably SDK
const ably = new Ably.Rest(process.env.ABLY_API_KEY);
const tokenRequest = await ably.auth.createTokenRequest({
  clientId: 'user-123',
  capability: JSON.stringify({
    'your-namespace:*': ['publish', 'subscribe'],
  }),
});
API key:
DEMO ONLY

Token capability determination

The capabilities of the resulting token are the intersection of the requested capabilities and those of the issuing API key. The token request will fail if the intersection is empty (the token would have no rights).

Note that a successful token request doesn't guarantee all requested capabilities were granted. If the issuing key's capabilities aren't known, verify the token has all required capabilities after creation.

Ably Token without capabilities

If no capability is specified in an Ably TokenRequest, then the Ably Token will be given the full set of capabilities assigned to the issuing key.

Using the following example, an API key exists with the listed capabilities. If an Ably Token is requested without specifying any capabilities then the TokenRequest is treated as requesting all capabilities, i.e. {"[*]*":["*"]}. This will result in the Ably Token receiving all the capabilities of the API key.

1

2

3

4

5

6

7

8

9

10

11

12

13

14

  // API key capabilities:
  {
    'your-namespace': ['publish', 'subscribe', 'presence'],
    'notifications': ['subscribe']
  }

  // Token request that doesn't specify any capabilities:
  await auth.requestToken(tokenCallback)

  // Resulting token capabilities:
  {
    'your-namespace': ['publish', 'subscribe', 'presence'],
    'notifications': ['subscribe']
  }
API key:
DEMO ONLY

Ably Token with intersection of capabilities

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.

Using the following example, an API key exists with the listed capabilities. If an Ably Token is requested and specifies a set of capabilities, then the resulting token will only receive those capabilities that intersect. The capabilities of a token cannot exceed those of the issuing API key.

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

  // API key capabilities:
  {
    'your-namespace:*': ['publish', 'subscribe', 'presence'],
    'notifications': ['subscribe', 'history'],
    'alerts': ['subscribe']
  }

  // Token request that specifies capabilities:
  const tokenDetails = await auth.requestToken({ capability: {
    'your-namespace:user-123': ['subscribe'], // only 'subscribe' intersects
    'notifications': ['*'], // '*'' intersects with 'subscribe'
    'private': ['publish', 'subscribe'] // key does not have access to 'private' channel
  }});

  // Resulting token capabilities:
  {
    'your-namespace:user-123': ['subscribe'],
    'notifications': ['subscribe', 'history']
  }
API key:
DEMO ONLY

Ably Token with incompatible capabilities

If a set of capabilities are requested, and the intersection between those and the API key's capabilities is empty, then the TokenRequest will result in an error.

Using the following example, an API key exists with the listed capabilities. If an Ably Token is requested that specifies a set of capabilities, and there is no intersection between the capabilities of the issuing API key and requested token, then the token request will be rejected. In the following example, the callback will be returned with an error.

1

2

3

4

5

6

7

8

9

  // API key capabilities:
  {
    'your-namespace': ['*']
  }

  // Token request that specifies capabilities:
  const tokenDetails = await auth.requestToken({ capability: {
    'other-namespace': ['*']
  }});
API key:
DEMO ONLY

Ably JWT capability determination

Capabilities are determined for JWTs in the following way:

  • The capabilities granted to an Ably JWT will be the intersection of the capabilities within the Ably JWT and 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.

Channel-scoped user claims

JWTs can contain channel-scoped user claims for trusted metadata that other clients can read. See JWT authentication — channel-scoped claims for details and examples.

Per-connection publish rate limits

JWTs can specify per-connection publish rate limits to restrict how many messages a client can send. See JWT authentication — rate limits for details and examples.