# Ably Tokens
Ably tokens are an alternative mechanism for authenticating with Ably.
They are not generated by a client but are issued by the Ably service via a `/requestToken` endpoint; a client generates a signed `Token Request` and this is exchanged for a token by the Ably service. Generally, integrating an application to use Ably tokens is more involved as Ably tokens also do not support all of the functionality available to JWTs.
[JWTs](https://ably.com/docs/auth/token/jwt.md) are the recommended mechanism for authenticating with Ably, however there are still some circumstances where the use of Ably tokens may be preferred:
- Your capability list is too large and exceeds JWT size limits (JWTs must fit within HTTP header limits, typically around 8 KB).
- You need to keep your capability list confidential, as JWTs can be decoded by clients.
## Choosing between TokenRequest and Ably Token (direct)
Ably tokens are always issued by the Ably service via a token request. The two flows differ in who performs the request and what is passed to the client:
### Server passes TokenRequest to client
Your server creates a signed `TokenRequest` using the Ably SDK. The client then exchanges this with Ably to get an actual token.
1. Your server creates a signed `TokenRequest` using the Ably SDK (no Ably API call needed).
2. Your server sends the `TokenRequest` to the client.
3. The client sends the `TokenRequest` to Ably, which returns an Ably Token.
Key characteristics:
- Server never contacts Ably. It just creates and signs the request locally.
- Client makes the token request to Ably.
### Server passes token to client
Your server requests a token directly from Ably and passes the ready-to-use token to the client.
1. Your server requests an Ably Token from Ably using the Ably SDK.
2. Ably returns the Ably Token to your server.
3. Your server sends the Ably Token to the client.
4. The client uses the Ably Token directly (no additional Ably contact needed).
Key characteristics:
- Server contacts Ably to get the token
- Client saves one round trip (doesn't need to contact Ably)
- Trade-off: server must communicate with Ably for each token
## TokenRequest
Using an Ably SDK, a `TokenRequest` is [generated from your server](https://ably.com/docs/api/realtime-sdk/authentication.md#create-token-request) and returned to the client-side SDK instance. The client-side SDK instance then uses the [`TokenRequest`](https://ably.com/docs/api/realtime-sdk/types.md#token-request) to request an Ably Token from Ably.

Key characteristics:
* A `TokenRequest` can be generated by your servers without communicating with Ably.
* Your secret API key is never shared with Ably or your clients.
* A `TokenRequest` cannot be tampered with due to being signed, must be used soon after creation, and can only be used once.
### Server examples
#### Javascript
```
const ably = new Ably.Rest({ key: 'your-api-key' });
const tokenRequest = await ably.auth.createTokenRequest({ clientId: 'client@example.com' });
// Return tokenRequest to client as JSON
```
#### Python
```
ably = AblyRest('your-api-key')
token = await ably.auth.create_token_request(
{
"clientId": "client@example.com",
"capability": {
"your-channel": ["publish", "subscribe"],
},
'ttl': 3600 * 1000, # ms
})
```
#### Java
```
ClientOptions options = new ClientOptions("your-api-key");
AblyRest rest = new AblyRest(options);
Auth.TokenParams tokenParams = new Auth.TokenParams();
tokenParams.clientId = "client@example.com";
Auth.TokenRequest tokenDetails = rest.auth.createTokenRequest(tokenParams, null);
```
#### Php
```
$rest = new Ably\AblyRest(
['key' => 'your-api-key']
);
$tokenRequest = $rest->auth->createTokenRequest(
['clientId' => 'client@example.com']
);
```
#### Go
```
rest, err := ably.NewREST(
ably.WithKey("your-api-key"))
if err != nil {
log.Fatalf("Error creating Ably client: %v", err)
}
tokenParams := &ably.TokenParams{ClientID: "client@example.com"}
tokenRequest, _ := rest.Auth.CreateTokenRequest(tokenParams)
```
#### Flutter
```
final clientOptions = ably.ClientOptions(
key: 'your-api-key',
);
final rest = ably.Rest(options: clientOptions);
const tokenParams = ably.TokenParams(
clientId: 'client@example.com'
);
final tokenRequest = rest.auth.createTokenRequest(tokenParams: tokenParams);
```
### Client usage
The client SDK automatically handles TokenRequests returned from your auth endpoint:
#### Realtime Javascript
```
const realtime = new Ably.Realtime({
authCallback: async (tokenParams, callback) => {
try {
const response = await fetch('/api/ably-token');
const tokenRequest = await response.json();
callback(null, tokenRequest);
} catch (error) {
callback(error, null);
}
},
});
```
#### Realtime Nodejs
```
const realtime = new Ably.Realtime({
authCallback: async (tokenParams, callback) => {
try {
const response = await fetch('/api/ably-token');
const tokenRequest = await response.json();
callback(null, tokenRequest);
} catch (error) {
callback(error, null);
}
},
});
```
#### Realtime Python
```
import aiohttp
async def get_token_request(*args, **kwargs):
async with aiohttp.ClientSession() as session:
async with session.get('/api/ably-token') as response:
if response.status != 200:
raise Exception(f"Auth failed: {response.status}")
return await response.json()
realtime = AblyRealtime(auth_callback=get_token_request)
```
#### Realtime Java
```
ClientOptions options = new ClientOptions();
options.authCallback = new Auth.TokenCallback() {
@Override
public Object getTokenRequest(Auth.TokenParams params) throws AblyException {
// Make HTTP request to your auth server and return TokenRequest
return fetchTokenRequestFromServer();
}
};
AblyRealtime realtime = new AblyRealtime(options);
```
#### Realtime Kotlin
```
val options = ClientOptions()
options.authCallback = Auth.TokenCallback { params ->
// Make HTTP request to your auth server and return TokenRequest
fetchTokenRequestFromServer()
}
val realtime = AblyRealtime(options)
```
#### Realtime Swift
```
let options = ARTClientOptions()
options.authCallback = { tokenParams, callback in
fetchTokenRequest { result in
switch result {
case .success(let tokenRequest):
callback(tokenRequest, nil)
case .failure(let error):
callback(nil, error)
}
}
}
let realtime = ARTRealtime(options: options)
```
#### Realtime Objc
```
ARTClientOptions *options = [[ARTClientOptions alloc] init];
options.authCallback = ^(ARTTokenParams *tokenParams, void (^callback)(id, NSError *)) {
[self fetchTokenRequest:^(id tokenRequest, NSError *error) {
if (error) {
callback(nil, error);
} else {
callback(tokenRequest, nil);
}
}];
};
ARTRealtime *realtime = [[ARTRealtime alloc] initWithOptions:options];
```
#### Realtime Csharp
```
ClientOptions options = new ClientOptions();
options.AuthCallback = async tokenParams =>
{
// Make HTTP request to your auth server and return TokenRequest
return await FetchTokenRequestFromServerAsync();
};
AblyRealtime realtime = new AblyRealtime(options);
```
#### Realtime Go
```
client, err := ably.NewRealtime(
ably.WithAuthCallback(func(ctx context.Context, params ably.TokenParams) (ably.Tokener, error) {
// Fetch TokenRequest from your auth server
return fetchTokenRequestFromServer()
}))
```
#### Realtime Ruby
```
realtime = Ably::Realtime.new(auth_callback: -> (token_params) {
# Fetch TokenRequest from your auth server
fetch_token_request_from_server()
})
```
#### Realtime Flutter
```
final clientOptions = ably.ClientOptions(
authCallback: (tokenParams) async {
// Fetch TokenRequest from your auth server
return await fetchTokenRequestFromServer();
},
);
final realtime = ably.Realtime(options: clientOptions);
```
## Ably Token (direct)
Using an Ably SDK, an Ably Token is [requested by your server](https://ably.com/docs/api/realtime-sdk/authentication.md#request-token) from Ably and then passed to the client. The client uses this token directly to authenticate. The client does not need to make an additional round trip to Ably.

Having the server obtain the token directly is generally more reliable. It minimizes the time delay between creation of the TokenRequest and requesting the token, and eliminates reliance on the accuracy of the clock in the client.
The main reason to prefer having the client request the token (via a TokenRequest) is scalability: if the server obtains the token directly, it must make a request to Ably for each client token, and this scales with the rate of token requests from clients.
### Server examples
#### Javascript
```
const ably = new Ably.Rest({ key: 'your-api-key' });
const tokenDetails = await ably.auth.requestToken({ clientId: 'client@example.com' });
// Return tokenDetails.token to client
```
#### Python
```
rest = AblyRest(key='your-api-key')
token_request_params = {
'clientId': 'client@example.com',
}
token_details = await rest.auth.request_token(token_params=token_request_params)
```
#### Java
```
ClientOptions options = new ClientOptions("your-api-key");
AblyRest rest = new AblyRest(options);
Auth.TokenParams tokenParams = new Auth.TokenParams();
tokenParams.clientId = "client@example.com";
Auth.TokenDetails tokenDetails = rest.auth.requestToken(tokenParams, null);
```
#### Php
```
$rest = new Ably\AblyRest(
['key' => 'your-api-key']
);
$tokenDetails = $rest->auth->requestToken(
['clientId' => 'client@example.com']
);
```
#### Go
```
rest, err := ably.NewREST(
ably.WithKey("API_KEY"))
if err != nil {
log.Fatalf("Error creating Ably client: %v", err)
}
tokenParams := &ably.TokenParams{ClientID: "client@example.com"}
tokenRequest, _ := rest.Auth.RequestToken(context.Background(), tokenParams)
```
#### Flutter
```
final clientOptions = ably.ClientOptions(
key: 'your-api-key',
);
final rest = ably.Rest(options: clientOptions);
const tokenParams = ably.TokenParams(
clientId: 'client@example.com',
);
final tokenDetails = await rest.auth.requestToken(
tokenParams: tokenParams
);
```
### Client usage
The client code for Ably Token direct is the same as for TokenRequest — the SDK handles the token transparently:
#### Realtime Javascript
```
const realtime = new Ably.Realtime({
authCallback: async (tokenParams, callback) => {
try {
const response = await fetch('/api/ably-token');
const tokenDetails = await response.json();
callback(null, tokenDetails);
} catch (error) {
callback(error, null);
}
},
});
```
#### Realtime Nodejs
```
const realtime = new Ably.Realtime({
authCallback: async (tokenParams, callback) => {
try {
const response = await fetch('/api/ably-token');
const tokenDetails = await response.json();
callback(null, tokenDetails);
} catch (error) {
callback(error, null);
}
},
});
```
#### Realtime Python
```
import aiohttp
async def get_ably_token(*args, **kwargs):
async with aiohttp.ClientSession() as session:
async with session.get('/api/ably-token') as response:
if response.status != 200:
raise Exception(f"Auth failed: {response.status}")
return await response.json()
realtime = AblyRealtime(auth_callback=get_ably_token)
```
#### Realtime Java
```
ClientOptions options = new ClientOptions();
options.authCallback = new Auth.TokenCallback() {
@Override
public Object getTokenRequest(Auth.TokenParams params) throws AblyException {
// Make HTTP request to your auth server and return token details
return fetchAblyTokenFromServer();
}
};
AblyRealtime realtime = new AblyRealtime(options);
```
#### Realtime Kotlin
```
val options = ClientOptions()
options.authCallback = Auth.TokenCallback { params ->
// Make HTTP request to your auth server and return token details
fetchAblyTokenFromServer()
}
val realtime = AblyRealtime(options)
```
#### Realtime Swift
```
let options = ARTClientOptions()
options.authCallback = { tokenParams, callback in
fetchAblyToken { result in
switch result {
case .success(let tokenDetails):
callback(tokenDetails, nil)
case .failure(let error):
callback(nil, error)
}
}
}
let realtime = ARTRealtime(options: options)
```
#### Realtime Objc
```
ARTClientOptions *options = [[ARTClientOptions alloc] init];
options.authCallback = ^(ARTTokenParams *tokenParams, void (^callback)(id, NSError *)) {
[self fetchAblyToken:^(ARTTokenDetails *tokenDetails, NSError *error) {
if (error) {
callback(nil, error);
} else {
callback(tokenDetails, nil);
}
}];
};
ARTRealtime *realtime = [[ARTRealtime alloc] initWithOptions:options];
```
#### Realtime Csharp
```
ClientOptions options = new ClientOptions();
options.AuthCallback = async tokenParams =>
{
// Make HTTP request to your auth server and return token details
return await FetchAblyTokenFromServerAsync();
};
AblyRealtime realtime = new AblyRealtime(options);
```
#### Realtime Go
```
client, err := ably.NewRealtime(
ably.WithAuthCallback(func(ctx context.Context, params ably.TokenParams) (ably.Tokener, error) {
// Fetch Ably Token from your auth server
return fetchAblyTokenFromServer()
}))
```
#### Realtime Ruby
```
realtime = Ably::Realtime.new(auth_callback: -> (token_params) {
# Fetch Ably Token from your auth server
fetch_ably_token_from_server()
})
```
#### Realtime Flutter
```
final clientOptions = ably.ClientOptions(
authCallback: (tokenParams) async {
// Fetch Ably Token from your auth server
return await fetchAblyTokenFromServer();
},
);
final realtime = ably.Realtime(options: clientOptions);
```
For embedded token JWTs, where you embed an Ably Token within an outer JWT used by your existing authentication system, see [Embedded Token JWT](https://ably.com/docs/auth/token.md#embedded).
## Related Topics
- [Overview](https://ably.com/docs/auth/token.md): Token authentication allows clients to authenticate with Ably, without exposing the Ably API key and secret.
- [JWTs](https://ably.com/docs/auth/token/jwt.md): JWT authentication is the recommended approach for authenticating clients with Ably. Create JWTs signed with your Ably API key.
## Documentation Index
To discover additional Ably documentation:
1. Fetch [llms.txt](https://ably.com/llms.txt) for the canonical list of available pages.
2. Identify relevant URLs from that index.
3. Fetch target pages as needed.
Avoid using assumed or outdated documentation paths.