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.