JSON Web Tokens (JWTs)

Open in

JSON Web Token (JWT) is the recommended token format for most applications. Your clients request a JWT from your server, which creates and signs it using your Ably API key. No Ably SDK is required on the server — any JWT library works.

Server setup

Creating JWTs

Your server creates JWTs signed with your Ably API key secret. No Ably SDK is required. Any JWT library works.

To generate JWTs in Node.js, install the jsonwebtoken package.

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

  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;

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

JWT claims

ClaimRequiredDescription
x-ably-capabilityYesJSON string defining capabilities
x-ably-clientIdNoSets a trusted client ID
expYesExpiration time (Unix timestamp)
iatYesIssued at time (Unix timestamp)

Client setup

authUrl is useful for web-based clients that can pass cookies automatically. For non-web clients, authCallback provides more control.

authCallback

Use authCallback to fetch JWTs from your server. The SDK automatically calls this function when connecting and when the token is near expiry.

Realtime

1

2

3

4

5

6

7

8

9

10

11

12

13

const realtime = new Ably.Realtime({
  authCallback: async (tokenParams, callback) => {
    try {
      const response = await fetch('/api/ably-token', {
        credentials: 'include',
      });
      if (!response.ok) throw new Error('Auth failed');
      callback(null, await response.text());
    } catch (error) {
      callback(error, null);
    }
  },
});

The tokenParams argument is available for convenience but should not be trusted. Your auth endpoint should authenticate clients separately using cookies, headers, or request body.

authUrl

You can specify an authUrl as an alternative to authCallback. The SDK makes an HTTP request to this URL to obtain a JWT.

Realtime
REST

1

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

AuthOptions

Use properties set with AuthOptions to customize authentication behavior:

  • authMethod - when authUrl is called, the default GET method will be used, unless POST is specified.
  • authHeaders - pass additional headers as required.
  • authParams - pass additional query parameters.
Realtime
REST

1

2

3

4

5

6

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

JWT features

JWTs support features not available with other token mechanisms.

Channel-scoped claims

Embed trusted metadata in JWTs that other clients can read. Use the ably.channel.* claim pattern:

JavaScript

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

const ablyJwt = jwt.sign(
  {
    'x-ably-capability': JSON.stringify({
      'chat:*': ['publish', 'subscribe', 'presence'],
    }),
    'x-ably-clientId': userId,
    // Channel-scoped claim - other clients can read this
    'ably.channel.chat:lobby': JSON.stringify({
      role: 'moderator',
      displayName: 'Alice',
    }),
  },
  keySecret,
  { algorithm: 'HS256', keyid: keyName, expiresIn: '1h' }
);

Other clients can read these claims from presence or message metadata, providing trusted user information without additional server calls.

Per-connection rate limits

Restrict how fast specific clients can publish messages using the ably.limits.publish.* claim:

JavaScript

1

2

3

4

5

6

7

8

9

10

const ablyJwt = jwt.sign(
  {
    'x-ably-capability': JSON.stringify({ '*': ['publish', 'subscribe'] }),
    'x-ably-clientId': userId,
    // Per-connection rate limit - max 10 messages per second
    'ably.limits.publish.perAttachment.maxRate.*': 10,
  },
  keySecret,
  { algorithm: 'HS256', keyid: keyName, expiresIn: '1h' }
);

Token lifecycle

Token refresh, TTL limits, and dynamic access control apply to all token types. See token authentication for details.

For a comparison of JWT, TokenRequest, and Ably Token mechanisms, see choosing a token mechanism.