If you integrate the Agora Chat SDK and Agora RTC SDK at the same time, Agora recommends you update the token-based authentication mechanism from AccessToken to AccessToken2.
This document uses the JAVA server and the Web client as examples to guide you how to build and update the token-based authentication mechanism step-by-step.
You have built a token server based on Spring Framework and a Web client using Agora Chat according to Authenticate Your Users with Tokens.
You have added the RTC Token service based on AccessToken to the token server of Agora Chat. To do this, in AgoraChatTokenController.java
file, import the RtcTokenBuilder
with import com.agora.chat.token.io.agora.media.RtcTokenBuilder;
and add the following method:
// Generate RTC AccessToken
@GetMapping("/rtc/{rtcChannelName}/{rtcUserId}/{role}/token")
public String getRtcToken(@PathVariable String rtcChannelName, @PathVariable int rtcUserId, @PathVariable int role) {
if (!StringUtils.hasText(appid) || !StringUtils.hasText(appcert)) {
return "appid or appcert is empty";
}
RtcTokenBuilder builder = new RtcTokenBuilder();
RtcTokenBuilder.Role rtcRole;
switch(role) {
case 1:
default:
rtcRole = RtcTokenBuilder.Role.Role_Publisher;
break;
case 2:
rtcRole = RtcTokenBuilder.Role.Role_Subscriber;
break;
}
return builder.buildTokenWithUid(appid, appcert, rtcChannelName, rtcUserId, rtcRole, expire);
}
You have added the authentication logic to the client using the using the RTC SDK. To do this, create a agoraRtcTokenClient
folder with the following two files:
index.html
:
<html>
<head>
<title>Token demo</title>
</head>
<body>
<h1>Token demo</h1>
<script src="https://download.agora.io/sdk/release/AgoraRTC_N.js"></script>
<script src="./client.js"></script>
</body>
</html>
client.js
. Replace <Your app ID>
with your App ID.
var rtc = {
// For the local audio and video tracks.
localAudioTrack: null,
localVideoTrack: null,
};
var options = {
// Pass your App ID here.
appId: "<Your app ID>",
// Set the channel name.
channel: "ChannelA",
// Set the user role as host (who can both send and receive streams) or audience (who can only receive streams).
role: "host",
};
// Fetch a token from the sever.
function fetchToken(uid, channelName, tokenRole) {
url = 'http://localhost:8090/rtc/' + channelName + '/' + uid + '/' + tokenRole + '/' + 'token'
return new Promise(function (resolve) {
fetch(url)
.then(res => res.text())
.then((token => { resolve(token); }))
})
.catch(function (error) {
console.log(error);
});
}
async function startBasicCall() {
const client = AgoraRTC.createClient({ mode: "live", codec: "vp8" });
client.setClientRole(options.role);
const uid = 123456;
// Fetch a token before calling join to join a channel.
let token = await fetchToken(uid, options.channel, 1);
await client.join(options.appId, options.channel, token, uid);
rtc.localAudioTrack = await AgoraRTC.createMicrophoneAudioTrack();
rtc.localVideoTrack = await AgoraRTC.createCameraVideoTrack();
await client.publish([rtc.localAudioTrack, rtc.localVideoTrack]);
const localPlayerContainer = document.createElement("div");
localPlayerContainer.id = uid;
localPlayerContainer.style.width = "640px";
localPlayerContainer.style.height = "480px";
document.body.append(localPlayerContainer);
rtc.localVideoTrack.play(localPlayerContainer);
console.log("publish success!");
client.on("user-published", async (user, mediaType) => {
await client.subscribe(user, mediaType);
console.log("subscribe success");
if (mediaType === "video") {
const remoteVideoTrack = user.videoTrack;
const remotePlayerContainer = document.createElement("div");
remotePlayerContainer.textContent =
"Remote user " + user.uid.toString();
remotePlayerContainer.style.width = "640px";
remotePlayerContainer.style.height = "480px";
document.body.append(remotePlayerContainer);
remoteVideoTrack.play(remotePlayerContainer);
}
if (mediaType === "audio") {
const remoteAudioTrack = user.audioTrack;
remoteAudioTrack.play();
}
client.on("user-unpublished", (user) => {
const remotePlayerContainer = document.getElementById(user.uid);
remotePlayerContainer.remove();
});
});
// When token-privilege-will-expire occurs, fetch a new token from the server and call renewToken to renew the token.
client.on("token-privilege-will-expire", async function () {
let token = await fetchToken(uid, options.channel, 1);
await client.renewToken(token);
});
// When token-privilege-did-expire occurs, fetch a new token from the server and call join to rejoin the channel.
client.on("token-privilege-did-expire", async function () {
console.log("Fetching the new Token");
let token = await fetchToken(uid, options.channel, 1);
console.log("Rejoining the channel with new Token");
await rtc.client.join(options.appId, options.channel, token, uid);
});
}
startBasicCall();
To test the AccessToken server, open index.html with a supported browser to perform the following actions:
To upgrade your authentication mechanism to AccessToken 2, use the following procedure.
This section shows you how to upgrade the token server to AccessToken2.
Import RtcTokenBuilder2
with the following code:
import com.agora.chat.token.io.agora.media.RtcTokenBuilder2;
Replace the code for getRtcToken
method with the following logic:
// Generate RTC AccessToken2
public String getRtcToken(@PathVariable String rtcChannelName, @PathVariable int rtcUserId, @PathVariable int role) {
if (!StringUtils.hasText(appid) || !StringUtils.hasText(appcert)) {
return "appid or appcert is empty";
}
RtcTokenBuilder2 builder = new RtcTokenBuilder2();
RtcTokenBuilder2.Role rtcRole;
switch(role) {
case 1:
default:
rtcRole = RtcTokenBuilder2.Role.ROLE_PUBLISHER;
break;
case 2:
rtcRole = RtcTokenBuilder2.Role.ROLE_SUBSCRIBER;
break;
}
return builder.buildTokenWithUid(appid, appcert, rtcChannelName, rtcUserId, rtcRole, expire);
}
No extra action is required for the client to get compatible with AccessToken2.
Open index.html
with a supported browser to perform the following actions:
This section introduces token generator libraries, version requirements, and related documents about AccessToken2.
AccessToken2 supports the following versions of the Agora RTC SDK:
SDK | First SDK version to support AccessToken2 |
---|---|
RTC Native SDK | 3.5.2 |
RTC ELectron SDK | 3.5.2 |
RTC Unity SDK | 3.5.2 |
RTC React Native SDK | 3.5.2 |
RTC Flutter SDK | 4.2.0 |
RTC Web SDK | 4.8.0 |
RTC WeChat Mini Program SDK | Not supported |
RTC SDKs that use AccessToken2 can interoperate with RTC SDKs that use AccessToken. Also, the RTC SDK that supports AccessToken2 also supports AccessToken.
Agora provides an open-source AgoraDynamicKey repository on GitHub, which enables you to generate AccessToken2 on your server with programming languages such as C++, Java, and Go.
Language | Algorithm | Core Method | Sample Code |
---|---|---|---|
C++ | HMAC-SHA256 | buildTokenWithUid | RtcTokenBuilder2Sample.cpp |
Go | HMAC-SHA256 | buildTokenWithUid | sample.go |
Java | HMAC-SHA256 | buildTokenWithUid | RtcTokenBuilder2Sample.java |
Node.js | HMAC-SHA256 | buildTokenWithUid | RtcTokenBuilder2Sample.js |
PHP | HMAC-SHA256 | buildTokenWithUid | RtcTokenBuilder2Sample.php |
Python | HMAC-SHA256 | buildTokenWithUid | RtcTokenBuilder2Sample.py |
Python3 | HMAC-SHA256 | buildTokenWithUid | RtcTokenBuilder2Sample.py |
Taking Java as an example, this section introduces the parameters and descriptions for the method to generate an AccessToken2.
public String buildTokenWithUid(String appId, String appCertificate, String channelName, int uid, Role role, int expire)
Parameter | Description |
---|---|
appId |
The App ID of your Agora project. |
appCertificate |
The App Certificate of your Agora project. |
channelName |
The channel name. The string length must be less than 64 bytes. Supported character scopes are:
|
uid |
The user ID of the user to be authenticated. A 32-bit unsigned integer with a value range from 1 to (2³² - 1). It must be unique. Set uid as 0, if you do not want to authenticate the user ID, that is, any uid from the app client can join the channel. |
role |
The privilege of the user, either as a publisher or a subscriber. This parameter determines whether a user can publish streams in the channel.
|
expire |
The Unix timestamp (in seconds) when an AccessToken expires. Set this parameter as the current timestamp plus the valid period of AccessToken2. For example, if you set expire as the current timestamp plus 600, the AccessToken2 expires in 10 minutes. An AccessToken2 is valid for 24 hours at most. If you set it to 0 or a period longer than 24 hours, the AccessToken2 is still valid for 24 hours. |
To facilitate privilege-level configuration in a channel, Agora provides an overloaded method to support configuring the expiration of the AccessToken2 and related privileges:
Take Java as an example:
public String buildTokenWithUid(String appId, String appCertificate, String channelName, int uid, int tokenExpire, int joinChannelPrivilegeExpire, int pubAudioPrivilegeExpire, int pubVideoPrivilegeExpire, int pubDataStreamPrivilegeExpire)
This method generates an RTC AccessToken2 and supports configuring the following privileges:
The privileges of publishing audio in an RTC channel, publishing video in an RTC channel, and publishing data stream in an RTC channel only take effect after enabling co-host authentication.
You can assign multiple privileges to a user. The maximum valid period of each privilege is 24 hours. When a privilege is about to expire or has expired, the RTC SDK triggers the onTokenPriviegeWillExpire
callback or the onRequestToken
callback. You need to take the following actions in your own app logic:
renewToken
to renew the AccessToken2, or joinChannel
to rejoin the channel. You need to set an appropriate expiration timestamp. For example, if the expiration time of joining a channel is earlier than that of publishing audio in the channel, when the privilege of joining a channel expires, the user is kicked out of the RTC channel. Even if the privilege of publishing audio is still valid, the privilege does not mean anything for the user.
Parameter | Description |
---|---|
tokenExpire |
Number of seconds passed from the generation of AccessToken2 to the expiration of AccessToken2. Set this parameter as the current timestamp plus the valid period of AccessToken2. For example, if you set tokenExpire as the current timestamp plus 600, the AccessToken2 expires in 10 minutes. An AccessToken2 is valid for 24 hours at most. If you set it to 0 or a period longer than 24 hours, the AccessToken2 is still valid for 24 hours. |
joinChannelPrivilegeExpire |
Number of seconds passed from the generation of AccessToken2 to the expiration of the privilege of joining a channel. Set this parameter as the current timestamp plus the valid period of the privilege of joining a channel. For example, if you set joinChannelPrivilegeExpire as the current timestamp plus 600, the privilege expires 10 minutes after generation. |
pubAudioPrivilegeExpire |
Number of seconds passed from the generation of AccessToken2 to the expiration of the privilege of publishing audio in a channel. Set this parameter as the current timestamp plus the valid period of publishing audio in a channel. For example, if you set pubAudioPrivilegeExpire as the current timestamp plus 600, the privilege expires 10 minutes after generation. If you do not want to enable this privilege, set this parameter to the current timestamp. |
pubVideoPrivilegeExpire |
Number of seconds passed from the generation of AccessToken2 to the expiration of the privilege of publishing video in a channel. Set this parameter as the current timestamp plus the valid period of publishing video in a channel. For example, if you set pubVideoPrivilegeExpire as the current timestamp plus 600, the privilege expires 10 minutes after generation. If you do not want to enable this privilege, set this parameter to the current timestamp. |
pubDataStreamPrivilegeExpire |
Number of seconds passed from the generation of AccessToken2 to the expiration of the privilege of publishing data stream in a channel. Set this parameter as the current timestamp plus the valid period of publishing video in a channel. For example, if you set pubDataStreamPrivilegeExpire as the current timestamp plus 600, the privilege expires 10 minutes after generation. If you do not want to enable this privilege, set this parameter to the current timestamp. |
Refer to the following steps to enable this function in Agora Console:
Co-host authentication takes effect in 5 minutes.
Once you have enabled co-host authentication, a user using your app must meet both of the following requirements to publish streams in a channel:
role
in setClientRole
is set as "BROADCASTER"
.role
in the code for generating tokens is set as ROLE_PUBLISHER
.