Users & Tokens
Creating users
Stream Users require only an ID to be created. Users can be created with the role of user or admin. The role will be set to user if a value is not provided in the request. There are additional properties you can provide to further describe your users.
The name
and image
fields are special fields that are supported by client-side SDKs.
You can provide additional data for the user object using the custom
field.
- JavaScript
- Python
- cURL
- JavaScript@0.3 (deprecated)
const newUser: UserRequest = {
id: 'userid',
role: 'user',
custom: {
color: 'red',
},
name: 'This is a test user',
image: 'link/to/profile/image',
};
await client.upsertUsers([newUser]);
from getstream.models import UserRequest
client.upsert_users(
UserRequest(
id="user_id",
role="user",
custom={"color": "red"},
name="This is a test user",
image="link/to/profile/image",
)
)
curl -X POST https://video.stream-io-api.com/api/v2/users?api_key=${API_KEY} \
-H "Authorization: ${TOKEN}" \
-H "stream-auth-type: jwt" \
-H "Content-Type: application/json" \
-d '{
"users": {
"john": {
"id": "john",
"role": "user",
"custom": {
"color": "red"
},
"name": "John",
"image": "link/to/profile/image"
}
}
}'
const userId = 'john';
const newUser: UserRequest = {
id: userId,
role: 'user',
custom: {
color: 'red',
},
name: 'John',
image: 'link/to/profile/image',
};
await client.upsertUsers({
users: {
[newUser.id]: newUser,
},
});
Updating users
There are two ways to update user objects:
- Updating will replace the existing user object
- Partial update will let you choose which fields you want to change/unset
- JavaScript
- Python
- cURL
- JavaScript@0.3 (deprecated)
const user: UserRequest = {
id: 'userid',
role: 'user',
custom: {
color: 'red',
},
name: 'This is a test user',
image: 'link/to/profile/image',
};
client.upsertUsers([user]);
// or
client.updateUsersPartial({
users: [
{
id: user.id,
set: {
color: 'blue',
},
unset: ['name'],
},
],
});
client.upsert_users(UserRequest(
id= 'userid',
role= 'user',
custom= {
"color": 'red',
},
name= 'This is a test user',
image= 'link/to/profile/image',
))
# or
client.update_users_partial(
users=[
UpdateUserPartialRequest(
id="userid",
set={
"color": "blue",
},
unset=["name"],
)
],
)
# Upserting a user, all existing user data will be overridden
curl -X POST https://video.stream-io-api.com/api/v2/users?api_key=${API_KEY} \
-H "Authorization: ${TOKEN}" \
-H "stream-auth-type: jwt" \
-H "Content-Type: application/json" \
-d '{
"users": {
"john": {
"id": "john",
"role": "user",
"custom": {
"color": "red"
},
"name": "John",
"image": "link/to/profile/image"
}
}
}'
# Partial update
curl -X PATCH https://video.stream-io-api.com/api/v2/users?api_key=${API_KEY} \
-H "Authorization: ${TOKEN}" \
-H "stream-auth-type: jwt" \
-H "Content-Type: application/json" \
-d '{
"users": [
{
"id": "john",
"set": {
"color": "blue"
},
"unset": ["name"]
}
]
}'
const user: UserRequest = {
id: 'userid',
role: 'user',
custom: {
color: 'red',
},
name: 'This is a test user',
image: 'link/to/profile/image',
};
client.upsertUsers({
users: {
[user.id]: user,
},
});
// or
client.updateUsersPartial({
users: [
{
id: user.id,
set: {
color: 'blue',
},
unset: ['name'],
},
],
});
Anonymous users
Anonymous users are users that are not authenticated. It's common to use this for watching a livestream or similar where you aren't authenticated. Anonymous users can be connected using client-side SDKs. Anonymous users are not counted toward your MAU.
Guest users
Guest users are temporary user accounts. You can use it to temporarily give someone a name and image when joining a call. Guest users can be created client-side. Guest users are counted towards your MAU usage.
Deactivating and deleting users
While it is usually safer for data retention to deactivate a user, some use cases require completely deleting a user and their data.
Deactivating a user means:
- the user can't connect to Stream API
- their data will be retained
- a deactivated user can be reactivated
- JavaScript
- Python
- cURL
client.deactivateUser({
user_id: '<id>',
});
//reactivate
client.reactivateUsers({
user_ids: ['<id>'],
});
// deactivativating users in bulk can take some time
const deactivateResponse = client.deactivateUsers({
user_ids: ['<id1>', '<id2>'...],
});
# deactivate one user
client.deactivate_user(user_id=alice.id)
# reactivates the user
client.reactivate_user(user_id=alice.id)
# deactivates users in bulk, this is an async operation
response = client.deactivate_users(user_ids=[alice.id, bob.id])
# Deactivate users
curl -X POST https://video.stream-io-api.com/api/v2/users/deactivate?api_key=${API_KEY} \
-H "Authorization: ${TOKEN}" \
-H "stream-auth-type: jwt" \
-H "Content-Type: application/json" \
-d '{
"user_ids": ["sara"]
}'
# Reactivate users
curl -X POST https://video.stream-io-api.com/api/v2/users/reactivate?api_key=${API_KEY} \
-H "Authorization: ${TOKEN}" \
-H "stream-auth-type: jwt" \
-H "Content-Type: application/json" \
-d '{
"user_ids": ["sara"]
}'
Deactivating users in bulk can take some time, this is how you can check the progress:
- JavaScript
- Python
- cURL
- JavaScript@0.3 (deprecated)
// Example of monitoring the status of an async task
// The logic is same for all async tasks
const response = await client.<async operation>();
// you need to poll this endpoint
const taskResponse = await client.getTask({id: response.task_id})
console.log(taskResponse.status === 'completed');
# Example of monitoring the status of an async task
# The logic is same for all async tasks
response = client.<async operation>()
task_id = response.data.task_id
# get information about the task
task_status = client.get_task(task_id)
# just an example, in reality it can take a few seconds for a task to be processed
if task_status.data.status == "completed":
print(task_status.data.result)
# When an operation is async, a task_id will be included in the API response
# That task_id can be used to monitor the status of the task
# When finished, task status will be completed
curl -X GET https://video.stream-io-api.com/api/v2/tasks/${TASK_ID}?api_key=${API_KEY} \
-H "Authorization: ${TOKEN}" \
-H "stream-auth-type: jwt"
// Example of monitoring the status of an async task
// The logic is same for all async tasks
const response = await client.<async operation>();
// you need to poll this endpoint
const taskResponse = await client.getTaskStatus({id: response.task_id})
console.log(taskResponse.status === 'completed');
For more informiation, please refer to the async operations guide
Deleting a user means:
- the user can't connect to Stream API
- their data won't appear in user queries
Delete has the following opitions:
Name | Type | Description | Optional |
---|---|---|---|
user | Enum (soft, pruning, hard) | - Soft: marks user as deleted and retains all user data. - Pruning: marks user as deleted and nullifies user information. - Hard: deletes user completely - this requires hard option for messages and conversation as well. | Yes |
conversations | Enum (soft, hard) | - Soft: marks all conversation channels as deleted (same effect as Delete Channels with 'hard' option disabled). - Hard: deletes channel and all its data completely including messages (same effect as Delete Channels with 'hard' option enabled). | Yes |
messages | Enum (soft, pruning, hard) | - Soft: marks all user messages as deleted without removing any related message data. - Pruning: marks all user messages as deleted, nullifies message information and removes some message data such as reactions and flags. - Hard: deletes messages completely with all related information. | Yes |
new_channel_owner_id | string | Channels owned by hard-deleted users will be transferred to this userID. If you doesn't provide a value, the channel owner will have a system generated ID like delete-user-8219f6578a7395g | Yes |
calls | Enum (soft, hard) | - Soft: marks calls and related data as deleted. - Hard: deletes calls and related data completely Note that this applies only to 1:1 calls, not group calls | Yes |
- JavaScript
- Python
- cURL
client.deleteUsers({ user_ids: ['<id>'] });
//restore
client.restoreUsers({ user_ids: ['<id>'] });
client.delete_users(user_ids=["<id>"])
# restore
client.restore_users(user_ids=["<id>"])
# Delete users
curl -X POST https://video.stream-io-api.com/api/v2/users/delete?api_key=${API_KEY} \
-H "Authorization: ${TOKEN}" \
-H "stream-auth-type: jwt" \
-H "Content-Type: application/json" \
-d '{
"user_ids": ["sara"]
}'
# Restore users
curl -X POST https://video.stream-io-api.com/api/v2/users/restore?api_key=${API_KEY} \
-H "Authorization: ${TOKEN}" \
-H "stream-auth-type: jwt" \
-H "Content-Type: application/json" \
-d '{
"user_ids": ["sara"]
}'
Deleting and restoring users in bulk can take some time, this is how you can check the progress:
- JavaScript
- Python
- cURL
- JavaScript@0.3 (deprecated)
// Example of monitoring the status of an async task
// The logic is same for all async tasks
const response = await client.<async operation>();
// you need to poll this endpoint
const taskResponse = await client.getTask({id: response.task_id})
console.log(taskResponse.status === 'completed');
# Example of monitoring the status of an async task
# The logic is same for all async tasks
response = client.<async operation>()
task_id = response.data.task_id
# get information about the task
task_status = client.get_task(task_id)
# just an example, in reality it can take a few seconds for a task to be processed
if task_status.data.status == "completed":
print(task_status.data.result)
# When an operation is async, a task_id will be included in the API response
# That task_id can be used to monitor the status of the task
# When finished, task status will be completed
curl -X GET https://video.stream-io-api.com/api/v2/tasks/${TASK_ID}?api_key=${API_KEY} \
-H "Authorization: ${TOKEN}" \
-H "stream-auth-type: jwt"
// Example of monitoring the status of an async task
// The logic is same for all async tasks
const response = await client.<async operation>();
// you need to poll this endpoint
const taskResponse = await client.getTaskStatus({id: response.task_id})
console.log(taskResponse.status === 'completed');
For more informiation, please refer to the async operations guide
User tokens
Stream uses JWT (JSON Web Tokens) to authenticate chat users, enabling them to log in. Knowing whether a user is authorized to perform certain actions is managed separately via a role-based permissions system. Tokens need to be generated server-side.
You can optionally provide an expiration time. By default, tokens are valid for 1 hour.
- JavaScript
- Python
- Bash
- JavaScript@0.3 (deprecated)
const userId = 'john';
// validity is optional (by default the token is valid for an hour)
const validity = 60 * 60;
client.generateUserToken({ user_id: userId, validity_in_seconds: validity });
# in this example we use Django
# but you can use any framework you like
import time
from django.contrib.auth.decorators import login_required
from django.http import JsonResponse
# The user token endpoint is protected with the login_required decorator.
@login_required
def create_user_token(request):
# The 'user_id' is retrieved from the request's user instance.
user_id = request.user.id
# the token will be valid for 1 hour
exp = 3600
# Here client is Stream client and it's called with the 'user_id' and the expiration time.
token = client.create_token(user_id, expiration=exp)
# The token is then returned in the response.
return JsonResponse({"token": token})
HEADER=$(echo -n '{"alg": "HS256", "typ": "JWT"}' | openssl base64 -e -A | tr '+/' '-_' | tr -d '=');
USER_ID='<user id>';
CURRENT_TIMESTAMP=$(date +%s);
HOUR_FROM_NOW=$((CURRENT_TIMESTAMP + 3600))
PAYLOAD=$(echo -n '{"user_id": "'${USER_ID}'", "iat": '${CURRENT_TIMESTAMP}', "exp": '${HOUR_FROM_NOW}'}' | openssl base64 -e -A | tr '+/' '-_' | tr -d '=');
SECRET='<API secret>';
SIGNATURE=$(echo -n ${HEADER}.${PAYLOAD} | openssl dgst -sha256 -hmac ${SECRET} -binary | openssl base64 -e -A | tr '+/' '-_' | tr -d '=');
echo "${HEADER}.${PAYLOAD}.${SIGNATURE}"
const userId = 'john';
// exp is optional (by default the token is valid for an hour)
const exp = Math.round(new Date().getTime() / 1000) + 60 * 60;
client.createToken(userId, exp);
You need to provide the generated tokens to the client SDKs. Stream SDKs accept a token provider, that can be called to retrieve and renew tokens. You need to implement the token provider in your own application, this is usually an HTTP endpoint.
Call tokens
Call tokens contain a list of call IDs. When a user utilizes a call token, they will automatically be assigned the membership role for all the calls specified in the token’s claims. Additionally, the token may optionally include alternative roles, such as admin or moderator.
Note: Call tokens are designed to grant additional access, not restrict it. Most call types let regular users join calls. If all users can access any call, call tokens won't change this. Remove call access from the user role and grant it to specific members instead.
- JavaScript
- Python
- Bash
- JavaScript@0.3 (deprecated)
const user_id = 'john';
// validity is optional (by default the token is valid for an hour)
const validity_in_seconds = 60 * 60;
const call_cids = ['default:call1', 'livestream:call2'];
client.generateCallToken({ user_id, call_cids, validity_in_seconds });
// Optionally provide a role for the call(s)
client.generateCallToken({ user_id, call_cids, role: 'admin' });
user_id = "john"
# exp and iat are optional, token will be valid for 1 hour
exp = 3600
call_cids = ["default:call1", "livestream:call2"]
client.create_call_token(user_id=user_id, expiration=exp, call_cids=call_cids)
HEADER=$(echo -n '{"alg": "HS256", "typ": "JWT"}' | openssl base64 -e -A | tr '+/' '-_' | tr -d '=');
USER_ID='<user id>';
CURRENT_TIMESTAMP=$(date +%s);
HOUR_FROM_NOW=$((CURRENT_TIMESTAMP + 3600))
CALL_CID1='livestream:1';
CALL_CID2='livestream:2';
# Optionally provide a role for the call(s)
ROLE='admin'
PAYLOAD=$(echo -n '{"user_id": "'${USER_ID}'", "role": "'${ROLE}'", "call_cids": ["'${CALL_CID1}'", "'${CALL_CID2}'"], "iat": '${CURRENT_TIMESTAMP}', "exp": '${HOUR_FROM_NOW}'}' | openssl base64 -e -A | tr '+/' '-_' | tr -d '=');
SECRET='<API secret>';
SIGNATURE=$(echo -n ${HEADER}.${PAYLOAD} | openssl dgst -sha256 -hmac ${SECRET} -binary | openssl base64 -e -A | tr '+/' '-_' | tr -d '=');
echo "${HEADER}.${PAYLOAD}.${SIGNATURE}"
const userId = 'john';
// exp is optional (by default the token is valid for an hour)
const exp = Math.round(new Date().getTime() / 1000) + 60 * 60;
const call_cids = ['default:call1', 'livestream:call2'];
client.createCallToken(userId, call_cids, exp);
// Optionally provide a role for the call(s)
client.createCallToken({ user_id: userId, role: 'admin' }, call_cids);