Stream uses JWT (JSON Web Tokens) to authenticate users so they can open WebSocket connections and send API requests. When a user opens your app, they first pass through your own authentication system. After that, the Stream SDK is initialized and a client instance is created. The device then requests a Stream token from your server. Your server verifies the request and returns a valid token. Once the device receives this token, the user is authenticated and ready to start using chat.
You can generate tokens on the server by creating a Server Client and then using the Create Token method.
If generating a token to use client-side, the token must include the userID claim in the token payload, whereas server tokens do not. When using the create token method, pass the user_id parameter to generate a client-side token.
// dotnet add package getstream-netusing GetStream;// Instantiate your Stream client using the API key and secret// the secret is only used server side and gives you full access to the API.var client = new StreamClient("{{ api_key }}", "{{ api_secret }}");var token = client.CreateUserToken("john");
// Define values.const api_key = "{{ api_key }}";const api_secret = "{{ api_secret }}";const user_id = "john";// Initialize a Server Clientconst serverClient = StreamChat.getInstance(api_key, api_secret);// Create User Tokenconst token = serverClient.createToken(user_id);
// For Gradle:// dependencies {// implementation "io.getstream:stream-sdk-java:$stream_version"// }StreamSDKClient client = new StreamSDKClient("{{ api_key }}", "{{ api_secret }}");String token = client.tokenBuilder().createToken("john");
// User Tokens must be generated server-side, check server-side SDKs for examples// For Testing/Development - read below how you can enable "Developer Tokens" and skip token generation for development purposes
You can use the JWT generator on this page to generate a User Token JWT without needing to set up a server client. You can use this token for prototyping and debugging; usually by hardcoding this into your application or passing it as an environment value at initialization.
You will need the following values to generate a token:
User ID : A unique string to identify a user.
API Secret : You can find this value in the Dashboard.
To generate a token, provide a User ID and your API Secret to the following generator:
For more information on how JWT works, please visit https://jwt.io.
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).
// creates a token that expires in 1 hour using moment.jsconst timestamp = Number(moment().add("1h").format("X"));const token1 = client.createToken("john", timestamp);// the same can be done with plain javascriptconst token2 = client.createToken( "john", Math.floor(Date.now() / 1000) + 60 * 60,);
# creates a token valid for 1 hourtoken = server_client.create_token("john", expiration=3600)
// creates a token valid for 1 hour$expiration = (new \DateTime())->getTimestamp() + 3600;$token = $client->createUserToken("john", expiration: $expiration);
// creates a token valid for 1 hourString token = client.tokenBuilder().createToken("john", 3600);
// creates a token valid for 1 hourtoken, _ := client.CreateToken("john", getstream.WithExpiration(time.Hour))
// 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
// creates a token valid for 1 hourvar token = client.CreateUserToken("john", expiration: TimeSpan.FromHours(1));
// user tokens must be generated server-side, check other languages for examples
// user tokens must be generated server-side, check other languages for examples
// User Tokens must be generated server-side, check server-side SDKs for examples// For Testing/Development - read below how you can enable "Developer Tokens" and skip token generation for development purposes
A concept we will refer to throughout the docs is a Token Provider. At a high level, the Token Provider is an endpoint on your server that can perform the following sequence of tasks:
Receive information about a user from the front end.
Validate that user information against your system.
Provide a User-ID corresponding to that user to the server client's token creation method.
For development applications, it is possible to disable token authentication and use client-side generated tokens or a manually generated static token. 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.
Select the App you want to enable developer tokens on and ensure it is in Development mode
Click App name to enter the Chat Overview
Scroll to the General section
Toggle Disable Authentication Checks
This disables the authentication check, but does not remove the requirement to send a token. Send either a client generated development token, or manually create one and hard code it into your application.
val user = User( id = "bender", name = "Bender", image = "https://bit.ly/321RmWb",)val token = client.devToken(user.id)client.connectUser(user, token).enqueue { /* ... */ }
User user = new User();user.setId("bender");user.setName("Bender");user.setImage("https://bit.ly/321RmWb");String token = client.devToken(user.getId());client.connectUser(user, token).enqueue(result -> { /* ... */ });
import StreamChat// Using a completion handlerchatClient.connectUser( userInfo: .init(id: "john-doe"), token: .development(userId: "john-doe")) { error in if let error = error { print("Connection failed with: \(error)") }}// or using async/awaittry await chatClient.connectUser( userInfo: .init(id: "john-doe"), token: .development(userId: "john-doe"))
final user = User(id: "john", extraData: { "name": "John Doe", "image": "https://getstream.io/random_svg/?name=John",});await client.setUser( user, client.devToken("john"),);
Token Revocation is a way to manually expire tokens for a single user or for many users by setting a revoke_tokens_issued_before time, and any tokens issued before this will be considered expired and will fail to authenticate. This can be reversed by setting the field to null.
from getstream.models import UpdateUserPartialRequestclient.update_users_partial(users=[ UpdateUserPartialRequest(id="user-id", set={"revoke_tokens_issued_before": revoke_date})])client.update_users_partial(users=[ UpdateUserPartialRequest(id=uid, set={"revoke_tokens_issued_before": revoke_date}) for uid in ["user1-id", "user2-id"]])
use GetStream\GeneratedModels as Models;$client->updateUsersPartial(new Models\UpdateUsersPartialRequest( users: [new Models\UpdateUserPartialRequest( id: "user-id", set: (object)["revoke_tokens_issued_before" => (new \DateTime())->format(\DateTime::ATOM)], )]));$client->updateUsersPartial(new Models\UpdateUsersPartialRequest( users: [ new Models\UpdateUserPartialRequest( id: "user1-id", set: (object)["revoke_tokens_issued_before" => (new \DateTime())->format(\DateTime::ATOM)], ), new Models\UpdateUserPartialRequest( id: "user2-id", set: (object)["revoke_tokens_issued_before" => (new \DateTime())->format(\DateTime::ATOM)], ), ]));
Models = GetStream::Generated::Modelsclient.common.update_users_partial( Models::UpdateUsersPartialRequest.new( users: [Models::UpdateUserPartialRequest.new( id: 'user-id', set: { 'revoke_tokens_issued_before' => before.iso8601 } )] ))client.common.update_users_partial( Models::UpdateUsersPartialRequest.new( users: ['user1-id', 'user2-id'].map { |uid| Models::UpdateUserPartialRequest.new( id: uid, set: { 'revoke_tokens_issued_before' => before.iso8601 } ) } ))# before should be a Time object
// dotnet add package getstream-netusing GetStream;using GetStream.Models;var client = new StreamClient("{{ api_key }}", "{{ api_secret }}");await client.UpdateUsersPartialAsync(new UpdateUsersPartialRequest{ Users = new List<UpdateUserPartialRequest> { new UpdateUserPartialRequest { ID = "<user-id>", Set = new Dictionary<string, object> { ["revoke_tokens_issued_before"] = DateTimeOffset.UtcNow.AddHours(-1) } } }});// Revoke tokens for multiple usersawait client.UpdateUsersPartialAsync(new UpdateUsersPartialRequest{ Users = new List<UpdateUserPartialRequest> { new UpdateUserPartialRequest { ID = "user1-id", Set = new Dictionary<string, object> { ["revoke_tokens_issued_before"] = DateTimeOffset.UtcNow.AddHours(-1) } }, new UpdateUserPartialRequest { ID = "user2-id", Set = new Dictionary<string, object> { ["revoke_tokens_issued_before"] = DateTimeOffset.UtcNow.AddHours(-1) } } }});
client.updateUsersPartial(UpdateUsersPartialRequest.builder() .users(List.of(UpdateUserPartialRequest.builder() .id("<user-id>") .set(Map.of("revoke_tokens_issued_before", new Date())) .build())) .build()).execute();client.updateUsersPartial(UpdateUsersPartialRequest.builder() .users(List.of( UpdateUserPartialRequest.builder() .id("<user1-id>") .set(Map.of("revoke_tokens_issued_before", new Date())) .build(), UpdateUserPartialRequest.builder() .id("<user2-id>") .set(Map.of("revoke_tokens_issued_before", new Date())) .build())) .build()).execute();
// This is a server-side feature
Note: Your tokens must include the iat (issued at time) claim, which will be compared to the time in the revoke_tokens_issued_before field to determine whether the token is valid or expired. Tokens which have no iat will be considered invalid.
from getstream.models import UpdateUserPartialRequestclient.update_users_partial(users=[ UpdateUserPartialRequest(id="user-id", unset=["revoke_tokens_issued_before"])])client.update_users_partial(users=[ UpdateUserPartialRequest(id=uid, unset=["revoke_tokens_issued_before"]) for uid in ["user1-id", "user2-id"]])
It is possible to revoke tokens for all users of an application. This should be used with caution as it will expire every user's token, regardless of whether the token has an iat claim.
await client.revokeTokens(revokeDate);// you can pass Date or ISOstring as value here
client.update_app(revoke_tokens_issued_before=revoke_time)# revoke_time is a datetime object
client.UpdateApp(ctx, &getstream.UpdateAppRequest{ RevokeTokensIssuedBefore: &revokeTime,})// revokeTime is a time.Time object
use GetStream\GeneratedModels as Models;$client->updateApp(new Models\UpdateAppRequest( revokeTokensIssuedBefore: new \DateTime("now"),));// revokeTokensIssuedBefore is a DateTime object
Models = GetStream::Generated::Modelsclient.common.update_app( Models::UpdateAppRequest.new(revoke_tokens_issued_before: before))# before is a Time object
// Revocation date must be at least 60 seconds in the pastCalendar cal = Calendar.getInstance();cal.add(Calendar.MINUTE, -2);client.updateApp(UpdateAppRequest.builder() .revokeTokensIssuedBefore(cal.getTime()) .build()).execute();
By default, user tokens generated through the createToken function do not contain information about time of issue. You can change that by passing the issue date as the third parameter while creating tokens. This is a security best practice, as it enables revoking tokens.
client.createToken("user-id", expireTime, issuedAt);// issuedAt should be unix timestamp// issuedAt = Math.floor(Date.now() / 1000)
token = server_client.create_token("user-id", expiration=expiry_seconds)# The token automatically includes the iat (issued at) claim
client.CreateToken("user-id", getstream.WithExpiration(expiryTime),)// expiryTime is a time.Duration (e.g. 24 * time.Hour)
$token = $client->createUserToken("user-id", expiration: $expiry, claims: ["iat" => $issuedAt]);// issuedAt should be unix timestamp
require 'jwt'token = JWT.encode( { user_id: 'john', exp: exp_time, iat: issued_at }, api_secret, 'HS256')# issued_at should be a unix timestamp
// creates a token valid for 2 hours// The token automatically includes the iat (issued at) claimvar token = client.CreateUserToken("user1-id", expiration: TimeSpan.FromHours(2));
// creates a token valid for 1 hour// The token automatically includes the iat (issued at) claimString token = client.tokenBuilder().createToken("john", 3600);