Authentication is the process of verifying whether a user has permission to access the system, to avoid security risks caused by missing or improper access control. ZEGO authenticates users through Token (including Basic Token and Privilege Token).
Developers must include a Token parameter when logging into a room to verify user legitimacy.
Basic Token is the fundamental capability of Token, used for simple permission verification scenarios. In most cases, generating this Token is sufficient.
To further improve security, Room ID and Stream ID privilege bits are exposed, allowing verification of the Room ID for login and Stream ID for publishing.
Common use cases for Room ID and Stream ID privilege bits include:
Distinguishing between regular and premium rooms, requiring control over non-premium users entering premium rooms.
In voice chat rooms or live streaming shows, ensuring that publishing users match on-mic users to prevent "ghost mic" phenomenon, where users hear audio from someone not on-mic.
In speaking games like Werewolf, preventing the app from being cracked by hackers who could log in with other user IDs to the same room and access game information for cheating, affecting normal users' experience.
Prerequisites
Warning
Only ZEGO Express SDK version 2.17.0 and later supports Token authentication as described in this document.
If you have integrated a ZEGO Express SDK version earlier than 2.17.0 (using AppSign authentication) and want to upgrade to version 2.17.0 with Token authentication, please refer to the How to upgrade from AppSign authentication to Token authentication document for more information about AppSign and Token authentication.
Process Overview
Scenario 1: Login Room Scenario
When using Token authentication, developers need to generate a Token first, then carry the Token to log in to a room. The ZEGO server verifies users with the Token.
The following describes the process using Token to determine whether a user can log in to a room:
The client initiates a Token request.
The Token is generated on the developer's server and returned to the client.
The client carries the obtained Token along with userID and roomID to log in to the corresponding room.
The ZEGO SDK automatically sends the Token to the ZEGO server for verification.
The ZEGO server returns the verification result to the ZEGO SDK.
The ZEGO SDK returns the verification result directly to the client. Clients without permission will fail to log in.
Scenario 2: Login to a Large-Scale Audio/Video Range Scene
Generate Token and login to a large-scale audio/video range scene
When using Token authentication, developers need to generate a Token first, then carry the Token to log in to a scene. The ZEGO server verifies users with the Token.
The following describes the process using Token to determine whether a user can log in to a scene:
The client initiates a Token request.
The Token is generated on the developer's server and returned to the client.
The client carries the obtained Token along with userID and sceneID to log in to the corresponding scene.
The ZEGO SDK automatically sends the Token to the ZEGO server for verification.
The ZEGO server returns the verification result to the ZEGO SDK.
The ZEGO SDK returns the verification result directly to the client. Clients without permission will fail to log in.
Generate and Use Token
This section describes in detail how developers can generate Tokens on the server, how to use Tokens, and how to handle Token expiration.
1 Get AppID and ServerSecret
To generate a Token, you need the unique identifier AppID and the ServerSecret of your project. Please obtain them from the "Project Information" section in Console - Project Management.
After obtaining the AppID and ServerSecret, developers can generate Tokens on their server according to their business needs. The client sends a Token request to the developer's server, and the developer's server generates the Token and returns it to the client.
2 Generate Token on the Server
Warning
For your convenience during development and debugging, we provide the ZEGO Token Assistant to generate temporary Tokens.
For business security, you must generate Tokens on your app server; Otherwise, there is a risk of ServerSecret being stolen.
After generating a Token on your own server, if you need to verify its validity, you can also use the ZEGO Token Assistant for verification.
ZEGO Token Assistant (Click to expand)
ZEGO Token Assistant
This tool runs locally in browser and does not send data to server. Do not expose ServerSecret in production, use for debugging only.
ZEGO provides an open-source zego_server_assistant plugin on GitHub/Gitee. Please use the "token04" version in the plugin to generate Tokens. The plugin supports Go, C++, Java, Objective-C, Python, PHP, .NET, and Node.js:
The user carries the obtained Token along with user and roomID information to log in to the corresponding room through the loginRoom interface.
Warning
The userID used when calling the loginRoom interface to log in must be the same as the userID used when "Generating Token on the Server".
String roomID = "xxx" // The ID of the room to log in to
ZegoUser user = new ZegoUser("xxxx");
ZegoRoomConfig config = new ZegoRoomConfig();
config.token = "xxxxxxxxxx"; // Obtain from the developer's server
engine.loginRoom(roomID, user, config);
String roomID = "xxx" // The ID of the room to log in to
ZegoUser user = new ZegoUser("xxxx");
ZegoRoomConfig config = new ZegoRoomConfig();
config.token = "xxxxxxxxxx"; // Obtain from the developer's server
engine.loginRoom(roomID, user, config);
NSString *roomID = @"xxx"; // The ID of the room to log in to
ZegoUser *user = [ZegoUser userWithUserID:@"xxxx"];
ZegoRoomConfig *config = [[ZegoRoomConfig alloc] init];
config.token = @"xxxxxxxx"; // Obtain from the developer's server
[[ZegoExpressEngine sharedEngine] loginRoom:roomID user:user config:config];
NSString *roomID = @"xxx"; // The ID of the room to log in to
ZegoUser *user = [ZegoUser userWithUserID:@"xxxx"];
ZegoRoomConfig *config = [[ZegoRoomConfig alloc] init];
config.token = @"xxxxxxxx"; // Obtain from the developer's server
[[ZegoExpressEngine sharedEngine] loginRoom:roomID user:user config:config];
std::string roomID = 'xxx'; // The ID of the room to log in to
ZegoUser user;
user.userID = 'xxxx';
user.userName = 'xxxx';
ZegoRoomConfig config;
config.token = 'xxxxxxxxxx' // Obtain from the developer's server
engine->loginRoom(roomID, user, config);
std::string roomID = 'xxx'; // The ID of the room to log in to
ZegoUser user;
user.userID = 'xxxx';
user.userName = 'xxxx';
ZegoRoomConfig config;
config.token = 'xxxxxxxxxx' // Obtain from the developer's server
engine->loginRoom(roomID, user, config);
let roomID = 'xxx' // The ID of the room to log in to
let token = 'xxxxxxxxxx' // Obtain from the developer's server
let user = {userID : 'xxxx'} // Unique user identifier in the room
let loginResult = await zg.loginRoom(roomID, token, user) // Log in to the room
let roomID = 'xxx' // The ID of the room to log in to
let token = 'xxxxxxxxxx' // Obtain from the developer's server
let user = {userID : 'xxxx'} // Unique user identifier in the room
let loginResult = await zg.loginRoom(roomID, token, user) // Log in to the room
string roomID = "xxx"; // The ID of the room to log in to
ZegoUser user = new ZegoUser();
user.userID = "xxxx";
user.userName = "xxxx";
ZegoRoomConfig config = new ZegoRoomConfig();
config.token = "xxxxxxxxxx"; // Obtain from the developer's server
engine.LoginRoom(roomID, user, config);
string roomID = "xxx"; // The ID of the room to log in to
ZegoUser user = new ZegoUser();
user.userID = "xxxx";
user.userName = "xxxx";
ZegoRoomConfig config = new ZegoRoomConfig();
config.token = "xxxxxxxxxx"; // Obtain from the developer's server
engine.LoginRoom(roomID, user, config);
var config = ZegoRoomConfig.defaultConfig();
config.token = 'your_token';
var user = ZegoUser('your_userID', 'your_userName');
ZegoExpressEngine.instance.loginRoom('your_roomID', user, config: config);
var config = ZegoRoomConfig.defaultConfig();
config.token = 'your_token';
var user = ZegoUser('your_userID', 'your_userName');
ZegoExpressEngine.instance.loginRoom('your_roomID', user, config: config);
let roomConfig = new ZegoRoomConfig()
roomConfig.token = 'xxxxxxxx' // Obtain from the developer's server
// Log in to the room
this.engine.loginRoom('your_room_id', new ZegoUser('user_id'), roomConfig)
let roomConfig = new ZegoRoomConfig()
roomConfig.token = 'xxxxxxxx' // Obtain from the developer's server
// Log in to the room
this.engine.loginRoom('your_room_id', new ZegoUser('user_id'), roomConfig)
let roomID = "xxx" // The ID of the room to log in to
let user = {userID: "xxxx", userName: "xxxx"};
let roomConfig = {token: "xxxxxxxxxx"}; // Obtain from the developer's server
ZegoExpressEngine.instance().loginRoom(roomID, user, config);
let roomID = "xxx" // The ID of the room to log in to
let user = {userID: "xxxx", userName: "xxxx"};
let roomConfig = {token: "xxxxxxxxxx"}; // Obtain from the developer's server
ZegoExpressEngine.instance().loginRoom(roomID, user, config);
If developers need to modify privilege bits after logging in to a room, they can also call the renewToken interface to update the Token. After the update, it will affect the permission for the next room login and stream publishing. Previously successful room logins and stream publishing will not be affected.
String token = getToken(); // Re-obtain Token from the developer's server
engine.renewToken(roomID, token);
String token = getToken(); // Re-obtain Token from the developer's server
engine.renewToken(roomID, token);
NSString *token = [MyToken getToken]; // Re-obtain Token from the developer's server
[[ZegoExpressEngine sharedEngine] renewToken:token roomID:roomID];
NSString *token = [MyToken getToken]; // Re-obtain Token from the developer's server
[[ZegoExpressEngine sharedEngine] renewToken:token roomID:roomID];
std::string token = getToken(); // Re-obtain Token from the developer's server
engine->renewToken(token);
std::string token = getToken(); // Re-obtain Token from the developer's server
engine->renewToken(token);
let token = await getToken(); // Re-obtain Token from the developer's server
zg.renewToken(token);
let token = await getToken(); // Re-obtain Token from the developer's server
zg.renewToken(token);
string token = getToken(); // Re-obtain Token from the developer's server
engine.RenewToken(token);
string token = getToken(); // Re-obtain Token from the developer's server
engine.RenewToken(token);
let token = 'xxxxxxxx' // Re-obtain Token from the developer's server
this.engine.renewToken('your_room_id', token)
let token = 'xxxxxxxx' // Re-obtain Token from the developer's server
this.engine.renewToken('your_room_id', token)
let token = getToken(); // Re-obtain Token from the developer's server
ZegoExpressEngine.instance().renewToken(roomID, token);
let token = getToken(); // Re-obtain Token from the developer's server
ZegoExpressEngine.instance().renewToken(roomID, token);
Scenario 2: Login to a Large-Scale Audio/Video Range Scene
Use Token to login to a large-scale audio/video range scene
The user carries the obtained Token along with user and sceneID information to log in to the corresponding scene.
Warning
The userID used when calling the loginScene interface to log in must be the same as the userID used when "Generating Token on the Server".
long sceneID = 123L; // The ID of the scene to log in to
ZegoUser user = new ZegoUser("xxxx");
ZegoSceneParam config = new ZegoSceneParam();
param.sceneID = sceneID;
param.user = user;
param.token = @"xxxxxxxx"; // Obtain from the developer's server
rangeScene.loginScene(param, new IZegoRangeSceneLoginSceneCallback() {
@Override
public void onLoginSceneCallback(int errorCode, ZegoSceneConfig config) {
}
});
long sceneID = 123L; // The ID of the scene to log in to
ZegoUser user = new ZegoUser("xxxx");
ZegoSceneParam config = new ZegoSceneParam();
param.sceneID = sceneID;
param.user = user;
param.token = @"xxxxxxxx"; // Obtain from the developer's server
rangeScene.loginScene(param, new IZegoRangeSceneLoginSceneCallback() {
@Override
public void onLoginSceneCallback(int errorCode, ZegoSceneConfig config) {
}
});
long long sceneID = 123; // The ID of the scene to log in to
ZegoUser *user = [ZegoUser userWithUserID:@"xxxx"];
ZegoSceneParam *param = [[ZegoSceneParam alloc] init];
param.sceneID = sceneID;
param.user = user;
param.token = @"xxxxxxxx"; // Obtain from the developer's server
[rangeScene loginScene:param callback:^(int errorCode, ZegoSceneConfig * _Nonnull config) {}];
long long sceneID = 123; // The ID of the scene to log in to
ZegoUser *user = [ZegoUser userWithUserID:@"xxxx"];
ZegoSceneParam *param = [[ZegoSceneParam alloc] init];
param.sceneID = sceneID;
param.user = user;
param.token = @"xxxxxxxx"; // Obtain from the developer's server
[rangeScene loginScene:param callback:^(int errorCode, ZegoSceneConfig * _Nonnull config) {}];
long long sceneID = 123; // The ID of the scene to log in to
ZegoUser user;
user.userID = 'xxxx';
user.userName = 'xxxx';
ZegoSceneParam param;
param.sceneID = sceneID;
param.user = user;
param.token = @"xxxxxxxx"; // Obtain from the developer's server
rangeScene->loginScene(param, [](int errorCode, const ZegoSceneConfig &config) {});
long long sceneID = 123; // The ID of the scene to log in to
ZegoUser user;
user.userID = 'xxxx';
user.userName = 'xxxx';
ZegoSceneParam param;
param.sceneID = sceneID;
param.user = user;
param.token = @"xxxxxxxx"; // Obtain from the developer's server
rangeScene->loginScene(param, [](int errorCode, const ZegoSceneConfig &config) {});
4 Token Expiration Handling
Warning
Token expiration may cause issues such as abnormal publishing and playing. Please strictly follow the instructions below to handle expired Tokens promptly.
Scenario 1: Login Room Scenario
30 seconds before Token expiration, the SDK will notify through the onRoomTokenWillExpire callback. After Token expiration, attempting to log in to a room will result in error code 1002078 (Token expired) received through onDebugError or onRoomStateChanged.
After receiving the Token-about-to-expire callback or the Token expired error code, developers need to obtain a new valid Token from their server and call the SDK's renewToken interface to update the Token.
If you have integrated ZEGO Express SDK version 2.17.0 or later, and do not call the renewToken interface to update the Token after it expires, the following behavior will occur when the permission expires:
Users who have already logged in will not be kicked out of the room.
Currently successful publishing and playing will not be affected. However, after stopping publishing, you will not be able to publish again unless you update the Token.
Note
ZEGO also provides another Token expiration handling mode, which can be configured by contacting ZEGO technical support:
Users who have already logged in will be kicked out of the room, and they can only log in again after updating the Token.
Currently successful publishing will be stopped.
@Override
public void onRoomTokenWillExpire(String roomID, int remainTimeInSecond){
String token = getToken(); // Re-obtain Token from the developer's server
engine.renewToken(roomID, token);
}
@Override
public void onRoomTokenWillExpire(String roomID, int remainTimeInSecond){
String token = getToken(); // Re-obtain Token from the developer's server
engine.renewToken(roomID, token);
}
- (void)onRoomTokenWillExpire:(int)remainTimeInSecond roomID:(NSString *)roomID {
NSString *token = [MyToken getToken]; // Re-obtain Token from the developer's server
[[ZegoExpressEngine sharedEngine] renewToken:token roomID:roomID];
}
- (void)onRoomTokenWillExpire:(int)remainTimeInSecond roomID:(NSString *)roomID {
NSString *token = [MyToken getToken]; // Re-obtain Token from the developer's server
[[ZegoExpressEngine sharedEngine] renewToken:token roomID:roomID];
}
void onRoomTokenWillExpire(const std::string& /*roomID*/, int /*remainTimeInSecond*/) override {
std::string token = getToken(); // Re-obtain Token from the developer's server
engine->renewToken(roomID, token);
}
void onRoomTokenWillExpire(const std::string& /*roomID*/, int /*remainTimeInSecond*/) override {
std::string token = getToken(); // Re-obtain Token from the developer's server
engine->renewToken(roomID, token);
}
zg.on('tokenWillExpire',(roomID: string)=>{
let token = await getToken(); // Re-obtain Token from the developer's server
zg.renewToken(token);
});
zg.on('tokenWillExpire',(roomID: string)=>{
let token = await getToken(); // Re-obtain Token from the developer's server
zg.renewToken(token);
});
void OnRoomTokenWillExpire(string roomID, int remainTimeInSecond){
string token = getToken(); // Re-obtain Token from the developer's server
engine.RenewToken(roomID, token);
}
void OnRoomTokenWillExpire(string roomID, int remainTimeInSecond){
string token = getToken(); // Re-obtain Token from the developer's server
engine.RenewToken(roomID, token);
}
ZegoExpressEngine.onRoomTokenWillExpire = (String roomID, int remainTimeInSecond) {
String token = getToken(); // Re-obtain Token from the developer's server
ZegoExpressEngine.instance.renewToken(roomID, token);
};
ZegoExpressEngine.onRoomTokenWillExpire = (String roomID, int remainTimeInSecond) {
String token = getToken(); // Re-obtain Token from the developer's server
ZegoExpressEngine.instance.renewToken(roomID, token);
};
onRoomTokenWillExpire(roomID: string, remainTimeInSecond: number): void {
let token = 'xxxxxxxx' // Re-obtain Token from the developer's server
this.engine.renewToken('your_room_id', token)
}
onRoomTokenWillExpire(roomID: string, remainTimeInSecond: number): void {
let token = 'xxxxxxxx' // Re-obtain Token from the developer's server
this.engine.renewToken('your_room_id', token)
}
ZegoExpressEngine.instance().on("roomTokenWillExpire", (roomID, remainTimeInSecond)=>{
let token = getToken(); // Re-obtain Token from the developer's server
ZegoExpressEngine.instance().renewToken(roomID, token);
});
ZegoExpressEngine.instance().on("roomTokenWillExpire", (roomID, remainTimeInSecond)=>{
let token = getToken(); // Re-obtain Token from the developer's server
ZegoExpressEngine.instance().renewToken(roomID, token);
});
Scenario 2: Range Scene Module
Token expiration handling in a large-scale audio/video range scene
30 seconds before Token expiration, the SDK will notify through the rangeScene callback. After Token expiration, attempting to log in to a room will result in error code 1002078 (Token expired) received through onDebugError or onRoomStateChanged.
After receiving the Token-about-to-expire callback or the Token expired error code, developers need to obtain a new valid Token from their server and call the SDK's renewToken interface to update the Token. If not handled, the Token expiration mechanism is as follows:
30 seconds before Token expiration, the SDK will notify through the onSceneTokenWillExpire callback. After Token expiration, attempting to log in to a room will result in error code 1002078 (Token expired) received through onDebugError or onRoomStateChanged.
After receiving the Token-about-to-expire callback or the Token expired error code, developers need to obtain a new valid Token from their server and call the SDK's renewToken interface to update the Token. If not handled, the Token expiration mechanism is as follows:
30 seconds before Token expiration, the SDK will notify through the onSceneTokenWillExpire callback. After Token expiration, attempting to log in to a room will result in error code 1002078 (Token expired) received through onDebugError or onRoomStateChanged.
After receiving the Token-about-to-expire callback or the Token expired error code, developers need to obtain a new valid Token from their server and call the SDK's renewToken interface to update the Token. If not handled, the Token expiration mechanism is as follows:
Users who have already logged in will not be kicked out of the scene.
Currently successful publishing and playing will not be affected, but the user's next publishing or playing operation will be affected.
public void onSceneTokenWillExpire(ZegoRangeScene rangeScene, int remainTimeInSecond) {
super.onSceneTokenWillExpire(rangeScene, remainTimeInSecond);
String token = getToken(); // Re-obtain Token from the developer's server
// Switch threads before calling renewToken
rangeScene.renewToken(token);
}
public void onSceneTokenWillExpire(ZegoRangeScene rangeScene, int remainTimeInSecond) {
super.onSceneTokenWillExpire(rangeScene, remainTimeInSecond);
String token = getToken(); // Re-obtain Token from the developer's server
// Switch threads before calling renewToken
rangeScene.renewToken(token);
}
- (void)rangeScene:(ZegoRangeScene *)rangeScene tokenWillExpire:(int)remainTimeInSecond {
NSString *token = [MyToken getToken]; // Re-obtain Token from the developer's server
// Switch threads before calling renewToken
[rangeScene renewToken:token];
}
- (void)rangeScene:(ZegoRangeScene *)rangeScene tokenWillExpire:(int)remainTimeInSecond {
NSString *token = [MyToken getToken]; // Re-obtain Token from the developer's server
// Switch threads before calling renewToken
[rangeScene renewToken:token];
}
void RangeScene::onSceneTokenWillExpire(IZegoRangeScene *rangeScene, int remainTimeInSecond) {
std::string token = getToken(); // Re-obtain Token from the developer's server
// Switch threads before calling renewToken
rangeScene->renewToken(token);
}
void RangeScene::onSceneTokenWillExpire(IZegoRangeScene *rangeScene, int remainTimeInSecond) {
std::string token = getToken(); // Re-obtain Token from the developer's server
// Switch threads before calling renewToken
rangeScene->renewToken(token);
}
Other
Generate and use Token on the client (not recommended)
If you are unable to deliver Tokens from the server during development, you can temporarily generate Tokens using client-side code, and complete the integration with the server later.
Warning
Do not generate Tokens on the client when your app goes live, otherwise your ServerSecret will be exposed to risk.
For security, it is strongly recommended to generate Tokens on the server, otherwise there is a risk of ServerSecret being stolen.
The following table lists the language-specific reference information for generating Tokens on the client using the zego_server_assistant plugin: