# Identified clients
When a client is authenticated and connected to Ably, it is considered to be an authenticated client. While an authenticated client has a means to authenticate with Ably, they do not necessarily have an identity.
When a client is assigned a trusted identity, that is, a `clientId`, then they are considered to be an identified client. For all operations that client performs with the Ably service, their `clientId` field will be automatically populated and can be trusted by other clients.
For example, assume you are building a chat application and want to allow clients to publish messages and be present on a channel. If each client is assigned a trusted identity by your server, such as a unique email address or UUID, then all other subscribed clients can trust any messages or presence events they receive in the channel as being from that client. No other clients are permitted to assume a `clientId` that they are not assigned in their Ably-compatible token. They are unable to masquerade as another `clientId`.
## ClientId immutability
A connection's `clientId`, once set, is immutable. You cannot change a `clientId` after it has been established for a connection.
### Late initialization
It is possible to have late initialization of `clientId` in certain scenarios:
* AuthCallback discovery: When using `authCallback`, the `clientId` may only become known when the first authCallback completes and returns a token with a `clientId`.
* Opaque token processing: When the library receives an opaque token string, it only learns the `clientId` when it receives a response from the server that has processed the token.
In both cases, the immutability requirement is satisfied because the `clientId` gets set as part of the client's first interaction with the server. Once this initial authentication is complete, the `clientId` cannot be changed for that connection.
## Assign a clientId
There are three different ways a client can be identified with using a `clientId`:
* A client claims a `clientId` when authenticating with an API key.
* A client is authenticating with a token issued for a specific `clientId`.
* A client claims a `clientId` when authenticating with a token that is issued for a wildcard `clientId`.
When a client sets their own ID there is the possibility that they can pretend to be someone else. To prevent this, it is recommended that you embed a `clientId` in the token issued to your clients from your auth server. This ensures that the `clientId` is set by your auth server, and eliminates the chance of a client pretending to be someone else.
### Basic auth
You can use [basic authentication](https://ably.com/docs/auth/basic) to allow a client to claim any `clientId` when they authenticate with Ably. As the assignation of the `clientId` is not handled by a server, it cannot be trusted to represent the genuine identity of the client.
### Token auth
You can use [token authentication](https://ably.com/docs/auth/token) to set an explicit `clientId` when creating or issuing a token. Clients using that token are restricted to operations for only that `clientId`, and all operations will implicitly contain that `clientId`.
For example, when publishing a message, the `clientId` attribute of the message will be pre-populated with that `clientId`. Entering presence will also implicitly use that `clientId`.
The following example demonstrates how to issue an [Ably TokenRequest](https://ably.com/docs/auth/token#token-request) with an explicit `clientId`:
```realtime_javascript
const realtime = new Ably.Realtime({ key: 'your-api-key' });
const tokenRequest = await realtime.auth.createTokenRequest({ clientId: 'Bob'});
```
```realtime_nodejs
const realtime = new Ably.Realtime({ key: 'your-api-key' });
const tokenRequest = await realtime.auth.createTokenRequest({ clientId: 'Bob'});
```
```realtime_ruby
realtime = Ably::Realtime.new(key: 'your-api-key')
realtime.auth.createTokenRequest(client_id: 'Bob') do |token_request|
# ... issue the TokenRequest to a client ...
end
```
```realtime_python
realtime = AblyRealtime(key='your-api-key')
token_request = await realtime.auth.create_token_request({'client_id': 'Bob'})
# ... issue the TokenRequest to a client ...
```
```realtime_java
ClientOptions options = new ClientOptions();
options.key = "your-api-key";
AblyRealtime realtime = new AblyRealtime(options);
TokenParams tokenParams = new TokenParams();
tokenParams.clientId = "Bob";
TokenRequest tokenRequest;
tokenRequest = realtime.auth.createTokenRequest(tokenParams, null);
/* ... issue the TokenRequest to a client ... */
```
```realtime_csharp
AblyRealtime realtime = new AblyRealtime("your-api-key");
TokenParams tokenParams = new TokenParams {ClientId = "Bob"};
string tokenRequest = await realtime.Auth.CreateTokenRequestAsync(tokenParams);
/* ... issue the TokenRequest to a client ... */
```
```realtime_objc
ARTRealtime *realtime = [[ARTRealtime alloc] initWithKey:@"your-api-key"];
ARTTokenParams *tokenParams = [[ARTTokenParams alloc] initWithClientId:@"Bob"];
[realtime.auth createTokenRequest:tokenParams options:nil
callback:^(ARTTokenRequest *tokenRequest NSError *error) {
// ... issue the TokenRequest to a client ...
}];
```
```realtime_swift
let realtime = ARTRealtime(key: "your-api-key")
let tokenParams = ARTTokenParams(clientId: "Bob")
realtime.auth.createTokenRequest(tokenParams, options: nil) { tokenRequest, error in
// ... issue the TokenRequest to a client ...
}
```
```realtime_go
realtime, _ := ably.NewRealtime(
ably.WithKey("your-api-key"))
params := &ably.TokenParams{
ClientID: "Bob",
}
tokenRequest, _ := realtime.Auth.CreateTokenRequest(params)
```
```realtime_flutter
final realtime = ably.Realtime(options: ably.ClientOptions(key: 'your-api-key'));
final tokenRequest = await realtime.auth.createTokenRequest(
tokenParams: ably.TokenParams(clientId: 'Bob'),
);
```
```rest_javascript
const rest = new Ably.Rest({ key: 'your-api-key' });
const tokenRequest = await realtime.auth.createTokenRequest({ clientId: 'Bob'});
```
```rest_nodejs
const rest = new Ably.Rest({ key: 'your-api-key' });
const tokenRequest = await realtime.auth.createTokenRequest({ clientId: 'Bob'});
```
```rest_ruby
rest = Ably::Rest.new(key: 'your-api-key')
token_request = rest.auth.create_token_request(client_id: 'Bob')
# ... issue the TokenRequest to a client ...
```
```rest_python
rest = AblyRest(key='your-api-key')
token_request = await rest.auth.create_token_request({'client_id': 'Bob'})
# ... issue the TokenRequest to a client ...
```
```rest_php
$rest = new Ably\AblyRest(
['key' => 'your-api-key']
);
$tokenRequest = $rest->auth->createTokenRequest(
['clientId' => 'Bob']
);
// ... issue the TokenRequest to a client ...
```
```rest_java
ClientOptions options = new ClientOptions();
options.key = "your-api-key";
AblyRest rest = new AblyRest(options);
TokenParams tokenParams = new TokenParams();
tokenParams.clientId = "Bob";
TokenRequest tokenRequest;
tokenRequest = rest.auth.createTokenRequest(tokenParams, null);
/* ... issue the TokenRequest to a client ... */
```
```rest_csharp
AblyRest rest = new AblyRest(new ClientOptions {Key = "your-api-key"});
TokenParams tokenParams = new TokenParams {ClientId = "Bob"};
string tokenRequest = await rest.Auth.CreateTokenRequestAsync(tokenParams);
// ... issue the TokenRequest to a client ...
```
```rest_objc
ARTRest *rest = [[ARTRest alloc] initWithKey:@"your-api-key"];
ARTTokenParams *tokenParams = [[ARTTokenParams alloc] initWithClientId:@"Bob"];
[rest.auth createTokenRequest:tokenParams options:nil
callback:^(ARTTokenRequest *tokenRequest, NSError *error) {
// ... issue the TokenRequest to a client ...
}];
```
```rest_swift
let rest = ARTRest(key: "your-api-key")
let tokenParams = ARTTokenParams(clientId: "Bob")
rest.auth.createTokenRequest(tokenParams, options: nil) { tokenRequest, error in
// ... issue the TokenRequest to a client ...
}
```
```rest_go
rest, _ := ably.NewREST(
ably.WithKey("your-api-key"))
params := &ably.TokenParams{
ClientID: "Bob",
}
tokenRequest, _ := rest.Auth.CreateTokenRequest(params)
```
```rest_flutter
final rest = ably.Rest(options: ably.ClientOptions(key: 'your-api-key'));
final tokenRequest = await rest.auth.createTokenRequest(
tokenParams: ably.TokenParams(clientId: 'Bob'),
);
```
### Wildcard token auth
You can use [token authentication](https://ably.com/docs/auth/token) to set a wildcard `clientId` using a value of `*` when creating a token. Clients are then able to assume any identity in their operations, such as when publishing a message or entering presence.
## Unidentified clients
If no `clientId` is provided when using [token authentication](https://ably.com/docs/auth/token) then clients are not permitted to assume an identity and will be considered an unidentified client in all operations. Messages published will contain no `clientId` and those clients will not be permitted to enter the [presence](https://ably.com/docs/presence-occupancy/presence) set.