Spaces authentication is handled by the underlying Pub/Sub SDK. You authenticate an Ably Realtime client, then pass that authenticated client into Spaces.
How Spaces maps to channels
A logical space is implemented using underlying Pub/Sub channels. Capability expressions should account for both channel types:
- Main space channel:
your-space(presence and member locations) - Cursors channel:
your-space-cursors(high-frequency cursor updates)
Authentication flow
- Your auth server authenticates the user.
- Your auth server issues an Ably-compatible token (JWT format is recommended for most apps).
- The client SDK fetches tokens with
authCallbackand refreshes them automatically before expiry. - The authenticated Pub/Sub client is passed into
Spaces.
Server setup
Create an endpoint that validates user-provided credentials and returns JWTs with the appropriate Spaces capabilities:
JavaScript
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
// Server-side JWT with space-scoped capabilities import jwt from 'jsonwebtoken'; const [keyName, keySecret] = process.env.ABLY_API_KEY.split(':'); const ablyJwt = jwt.sign( { 'x-ably-capability': JSON.stringify({ 'your-space': ['publish', 'subscribe', 'presence', 'history'], 'your-space-cursors': ['publish', 'subscribe'], }), 'x-ably-clientId': userId, }, keySecret, { algorithm: 'HS256', keyid: keyName, expiresIn: '1h' } );Client setup
JavaScript
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
import Spaces from '@ably/spaces'; import { Realtime } from 'ably'; const realtimeClient = new Realtime({ authCallback: async (tokenParams, callback) => { try { const response = await fetch('/api/ably-token', { credentials: 'include' }); if (!response.ok) throw new Error('Auth failed'); const jwt = await response.text(); callback(null, jwt); } catch (error) { callback(error, null); } }, }); const spaces = new Spaces(realtimeClient);In each example, the authenticated Pub/Sub client is passed into Spaces and Spaces uses that connection for authentication and token renewal.
Spaces capabilities
| Feature area | Required capabilities |
|---|---|
| Member locations and avatar stack | subscribe, presence |
| Live cursors | publish, subscribe |
| Component locking | subscribe, presence |
| History-aware collaboration | history |
Space-scoped capabilities
You can scope capabilities to specific spaces or all spaces:
my-space- a specific space and its associated channelsmy-namespace:*- all spaces in themy-namespace:namespace*- all spaces
Token lifecycle and permission updates
- With
authCallbackorauthUrl, token refresh is automatic and handled by the SDK. - To change a user's capabilities during an active session, issue a new token from your auth server and re-authenticate:
JavaScript
1
2
// Re-authenticate to pick up updated capabilities await realtimeClient.auth.authorize();- To immediately remove access, revoke issued tokens.
- If your capability JSON is too large for JWT or must remain confidential, use native Ably Tokens.