Tokens & Authentication

LAST EDIT Feb 22 2021

TokensCopied!

Tokens are used to authenticate the user. Typically, you send this token from your backend to the client-side when a user registers or logs in.

You can generate tokens server side with the following syntax:

1
2
const client = new StreamChat('chat_api_key', 'chat_api_secret'); 
const token = client.createToken('john');
1
2
3
4
5
6
# pip install stream-chat 
 
import stream_chat 
 
chat_client = stream_chat.StreamChat(api_key="STREAM_KEY", api_secret="STREAM_SECRET") 
token = chat_client.create_token('john')
1
2
3
4
5
6
# gem install stream-chat-ruby 
 
require 'stream-chat' 
 
client = StreamChat::Client.new(api_key='STREAM_KEY', api_secret='STREAM_SECRET') 
client.create_token('john')
1
2
3
4
// composer require get-stream/stream-chat 
 
$client = new GetStream\StreamChat\Client("STREAM_API_KEY", "STREAM_API_SECRET"); 
$token = $client->createToken("john");
1
// at the moment we don't have a Java client for server side usage
1
2
3
4
// go get github.com/GetStream/stream-chat-go 
 
client, _ := stream.NewClient(APIKey, []byte(APISecret)) 
token := client.CreateToken("john", time.Time{})
1
2
// at the moment we don't have a Swift client for server side usage 
// You can use our user token generator here during development: https://getstream.io/chat/docs/token_generator/?language=swift
1
2
3
4
5
6
// nuget install stream-chat-net 
 
using StreamChat; 
 
var client = new Client("API KEY", "API SECRET"); 
var token = client.CreateUserToken("john");
1
// user tokens must be generated server-side, check other languages for examples
1
// user tokens must be generated server-side, check other languages for examples

By default, user tokens are valid indefinitely. You can set an expiration to tokens by passing it as the second parameter. The expiration should contain the number of seconds since Unix epoch (00:00:00 UTC on 1 January 1970).

1
2
3
4
5
6
// creates a token that expires in 1 hour using moment.js 
const timestamp = Number(moment().add('1h').format('X')); 
const token1 = client.createToken('john', timestamp); 
 
// the same can be done with plain javascript 
const token2 = client.createToken('john', Math.floor(Date.now() / 1000) + (60 * 60));
1
2
3
4
5
# creates a token valid for 1 hour 
token = chat_client.create_token( 
    'john', 
    exp=datetime.datetime.utcnow() + datetime.timedelta(hours=1) 
)
1
2
# creates a token valid for 1 hour 
client.create_token('john', exp=Time.now.to_i + 3600)
1
2
3
// creates a token valid for 1 hour 
$expiration = (new DateTime())->getTimestamp() + 3600; 
$token = $client->createToken("john", $expiration);
1
// at the moment we don't have a Java SDK for server side integrations
1
2
// creates a token valid for 1 hour 
token := client.CreateToken("john", time.Now().UTC().Add(time.Hour))
1
2
// at the moment we don't have a Swift client for server side usage 
// You can use our user token generator here during development: https://getstream.io/chat/docs/token_generator/?language=swift
1
2
// creates a token valid for 1 hour 
var token = client.CreateUserToken("john", DateTime.Now.AddHours(1));
1
// user tokens must be generated server-side, check other languages for examples
1
// user tokens must be generated server-side, check other languages for examples

Development TokensCopied!

For development applications, it is possible to disable token authentication and use client-side generated tokens. Disabling auth checks is not suitable for a production application and should only be done for proofs-of-concept and applications in the early development stage. To enable development tokens, you need to change your application configuration - On the Dashboard, Go to App -> Chat -> Chat Overview -> Disable Auth Checks (Enable this option so creating development tokens is possible)

1
2
3
4
5
6
7
8
await client.connectUser( 
    { 
        id: 'john', 
        name: 'John Doe', 
        image: 'https://getstream.io/random_svg/?name=John', 
    }, 
   client.devToken('john'), 
);
1
2
3
4
5
6
7
8
9
10
11
User user = new User(); 
user.setId("bender"); 
 
HashMap<String, Object> extraData = new HashMap<>(); 
extraData.put("name", "Bender"); 
extraData.put("image", "https://bit.ly/321RmWb"); 
user.setExtraData(extraData); 
 
String token = client.devToken(user.getId()); 
 
client.connectUser(user, token).enqueue(result -> { /* ... */ });
1
2
3
4
5
6
7
8
9
10
import StreamChat 
 
/// 1: Create a development token provider. Use it for testing purposes. 
let tokenProvider = TokenProvider.development(userId: "john-doe") 
 
/// 2: Create a `ChatClientConfig` with the API key. 
let config = ChatClientConfig(apiKeyString: "YOUR_API_KEY") 
 
/// 3: Create a `ChatClient` instance with the config and the token provider. 
chatClient = ChatClient(config: config, tokenProvider: tokenProvider)
1
2
3
4
5
6
7
8
9
10
val user = User( 
    id = "bender", 
    extraData = mutableMapOf( 
        "name" to "Bender", 
        "image" to "https://bit.ly/321RmWb", 
    ), 
) 
val token = client.devToken(user.id) 
 
client.connectUser(user, token).enqueue { /* ... */ }
1
2
3
4
5
6
7
8
9
final user = User(id: "john", extraData: { 
  "name": "John Doe", 
  "image": "[object Object]", 
}); 
 
await client.setUser( 
  user, 
  client.devToken("john"), 
);
The above code used the connectUser call. The connectUser call is the most convenient option when your app has authenticated users. Alternatively, you can use setGuestUser if you want to allow users to chat with a guest account or the connectAnonymousUser if you want to allow anonymous users to watch the chat.

Token ExpirationCopied!

If you're using tokens with an expiration date you'll want to update tokens as soon as a token exception occurs. Our React, RN, iOS, Android and Flutter libraries have built-in support for this.

Here is the regular flow to handle tokens with expiration with a token provider:

  1. Chat is initialized using the API Key and the token provider

  2. The Chat client will use the token provider to fetch the token when connectUser is called

  3. When the token expires, the API will return a specific Authentication error code

  4. The client will pause API requests and use the token provider to obtain a fresh token

  5. The token provider returns a new token (ie. from your backend)

  6. Chat client replaces the old token with the new one and use it for all waiting and future API calls

A token provider is a function or class that you implement and that is responsible for requesting a new token from your own login infrastructure.

The most common token provider implementation does an HTTP call to your backend with the ID of the user as well as a valid session id or secret needed to authenticate them.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
User user = new User(); 
user.setId("bender"); 
 
HashMap<String, Object> extraData = new HashMap<>(); 
extraData.put("name", "Bender"); 
extraData.put("image", "https://bit.ly/321RmWb"); 
user.setExtraData(extraData); 
 
TokenProvider tokenProvider = new TokenProvider() { 
    @NotNull 
    @Override 
    public String loadToken() { 
        return yourTokenService.getToken(user); 
    } 
}; 
client.connectUser(user, tokenProvider).enqueue(result -> { /* ... */ });
1
2
3
4
5
6
7
8
9
10
11
12
13
val user = User( 
    id = "bender", 
    extraData = mutableMapOf( 
        "name" to "Bender", 
        "image" to "https://bit.ly/321RmWb", 
    ), 
) 
 
val tokenProvider = object : TokenProvider { 
    // Make a request to your backend to generate a valid token for the user 
    override fun loadToken(): String = yourTokenService.getToken(user) 
} 
client.connectUser(user, tokenProvider).enqueue { /* ... */ }
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
//> import StreamChat 
 
/// 1: Create a token provider that fetches the token from your backend service. 
let tokenProvider = TokenProvider.closure { chatClient, completion in 
    let token: Token? = nil 
    let error: Error? = nil 
 
    /// TODO: Fetch a token locally or use URLSession/Alamofire/etc to fetch 
    /// a token from your backend service and pass it into completion 
 
    if let token = token { 
        completion(.success(token)) 
    } else if let error = error { 
        completion(.failure(error)) 
    } 
} 
 
/// 2: Create a `ChatClientConfig` with the API key. 
let config = ChatClientConfig(apiKeyString: "YOUR_API_KEY") 
 
/// 3: Create a `ChatClient` instance with the config and the token provider. 
chatClient = ChatClient(config: config, tokenProvider: tokenProvider)
1
2
3
4
5
6
7
8
9
10
11
const client = new StreamChat('api_key'); 
const userID = 'vishal'; 
 
client.connectUser( 
    { id: userID }, 
    async () => { 
        // make a request to your own backend to get the token 
        const response = await httpBackend.post("/chat-token/", {userID}); 
        return response.token; 
    } 
);

Guest UsersCopied!

Guest sessions can be created client-side and do not require any server-side authentication.

Guest users have a limited set of permissions. You can read more about how to configure permissions here. You can create a guest user session by using setGuestUser instead of connectUser.

1
await client.setGuestUser({ id: 'tommaso' });
1
client.connectGuestUser("bender", "Bender").enqueue(result -> { /* ... */ });
1
2
3
4
5
6
7
8
9
10
import StreamChat 
 
/// 1: Create a guest token provider. 
let tokenProvider = TokenProvider.guest(userId: "john-doe") 
 
/// 2: Create a `ChatClientConfig` with the API key. 
let config = ChatClientConfig(apiKeyString: "YOUR_API_KEY") 
 
/// 3: Create a `ChatClient` instance with the config and the token provider. 
chatClient = ChatClient(config: config, tokenProvider: tokenProvider)
1
client.connectGuestUser(userId = "bender", username = "Bender").enqueue { /*... */ }
1
await client.setGuestUser(user);
The user object schema is the same as the one described in the Setting the user portion of the docs.

Anonymous UsersCopied!

If a user is not logged in, you can call the connectAnonymousUser method. While you’re anonymous, you can’t do much, but for the livestream channel type, you’re still allowed to read the chat conversation.

1
await client.connectAnonymousUser();
1
client.connectAnonymousUser().enqueue(result -> { /* ... */ });
1
Client.shared.setAnonymousUser()
1
2
3
4
5
6
7
8
9
10
import StreamChat 
 
/// 1: Create an anonymous token provider. 
let tokenProvider = TokenProvider.anonymous 
 
/// 2: Create a `ChatClientConfig` with the API key. 
let config = ChatClientConfig(apiKeyString: "YOUR_API_KEY") 
 
/// 3: Create a `ChatClient` instance with the config and the token provider. 
chatClient = ChatClient(config: config, tokenProvider: tokenProvider)
1
await client.setAnonymousUser();

Logging Out & Switching UsersCopied!

To disconnect a user (say that you’re for instance logging out and logging in as someone new) you can call the disconnect method and repeat the connectUser call as someone else:

1
2
3
4
5
6
7
8
client.disconnect(); 
client.connectUser( 
    { 
        id: 'jack', 
        name: 'Jack Doe', 
    }, 
    'CHAT_USER_TOKEN', 
);
1
2
client.disconnect(); 
client.connectUser(user, token).enqueue(result -> { /* ... */ });
1
2
3
4
import StreamChat 
 
chatClient.tokenProvider = .static(Token("CHAT_USER_TOKEN")) 
chatClient.currentUserController().reloadUserIfNeeded()
1
2
client.disconnect() 
client.connectUser(user, token).enqueue { /* ... */ }
1
2
3
4
5
6
7
8
9
10
await client.disconnect(); 
 
final otherUser = User(id: "jack", extraData: { 
  "name": "Jack Doe", 
}); 
 
await client.setUser( 
  otherUser, 
  client.devToken("{{ chat_user_token }}"), 
);