Upgrade from AccessToken to AccessToken2
This section introduces how to use AccessToken to authenticate your users and how to upgrade from AccessToken to AccessToken2.
The following figure shows the steps in the authentication flow:
A token is a dynamic key generated on your app server that is valid for a maximum of 24 hours. When your users connect to an Agora channel from your app client, Agora Platform validates the token and reads the user and project information stored in the token. A token contains the following information:
- The App ID of your Agora project
- The channel name
- The user ID of the user to be authenticated
- The privilege of the user, either as a publisher or a subscriber
- The time after which the token expires
In order to follow this procedure you must have the following:
This section shows you how to supply and consume a token that gives rights to specific functionality to authenticated users using the source code provided by Agora.
This section shows you how to get the security information needed to generate a token, including the App ID and App Certificate of your project.
Agora automatically assigns each project an App ID as a unique identifier.
To copy this App ID, find your project on the Project Management page in Agora Console, and click the copy icon in the App ID column.
To get an App Certificate, do the following:
- On the Project Management page, click Config for the project you want to use.
- Click the copy icon under Primary Certificate.
Token generators create the tokens requested by your client app to enable secure access to Agora Platform. To serve these tokens you deploy a generator in your security infrastructure.
In order to show the authentication workflow, this section shows how to build and run a token server written in Golang on your local machine.
This sample server is for demonstration purposes only. Do not use it in a production environment.
-
Create a file, server.go
, with the following content. Then replace <Your App ID>
and <Your App Certificate>
with your App ID and App Certificate.
_128 rtctokenbuilder "github.com/AgoraIO/Tools/DynamicKey/AgoraDynamicKey/go/src/RtcTokenBuilder"
_128type rtc_int_token_struct struct{
_128 Uid_rtc_int uint32 `json:"uid"`
_128 Channel_name string `json:"ChannelName"`
_128 Role uint32 `json:"role"`
_128var channel_name string
_128var role rtctokenbuilder.Role
_128// Use RtcTokenBuilder to generate an <Vg k="VSDK" /> token.
_128func generateRtcToken(int_uid uint32, channelName string, role rtctokenbuilder.Role){
_128 appID := "<Your App ID>"
_128 appCertificate := "<Your App Certificate>"
_128 // Number of seconds after which the token expires.
_128 // For demonstration purposes the expiry time is set to 40 seconds. This shows you the automatic token renew actions of the client.
_128 expireTimeInSeconds := uint32(40)
_128 // Get current timestamp.
_128 currentTimestamp := uint32(time.Now().UTC().Unix())
_128 // Timestamp when the token expires.
_128 expireTimestamp := currentTimestamp + expireTimeInSeconds
_128 result, err := rtctokenbuilder.BuildTokenWithUID(appID, appCertificate, channelName, int_uid, role, expireTimestamp)
_128 fmt.Printf("Token with uid: %s\n", result)
_128 fmt.Printf("uid is %d\n", int_uid )
_128 fmt.Printf("ChannelName is %s\n", channelName)
_128 fmt.Printf("Role is %d\n", role)
_128 func rtcTokenHandler(w http.ResponseWriter, r *http.Request){
_128 w.Header().Set("Content-Type", "application/json; charset=UTF-8")
_128 w.Header().Set("Access-Control-Allow-Origin", "*")
_128 w.Header().Set("Access-Control-Allow-Methods", "POST, OPTIONS");
_128 w.Header().Set("Access-Control-Allow-Headers", "*");
_128 if r.Method == "OPTIONS" {
_128 w.WriteHeader(http.StatusOK)
_128 if r.Method != "POST" && r.Method != "OPTIONS" {
_128 http.Error(w, "Unsupported method. Please check.", http.StatusNotFound)
_128 var t_int rtc_int_token_struct
_128 var unmarshalErr *json.UnmarshalTypeError
_128 int_decoder := json.NewDecoder(r.Body)
_128 int_err := int_decoder.Decode(&t_int)
_128 if (int_err == nil) {
_128 int_uid = t_int.Uid_rtc_int
_128 channel_name = t_int.Channel_name
_128 role_num = t_int.Role
_128 // DEPRECATED. RoleAttendee has the same privileges as RolePublisher.
_128 role = rtctokenbuilder.RoleAttendee
_128 role = rtctokenbuilder.RolePublisher
_128 role = rtctokenbuilder.RoleSubscriber
_128 // DEPRECATED. RoleAdmin has the same privileges as RolePublisher.
_128 role = rtctokenbuilder.RoleAdmin
_128 if (int_err != nil) {
_128 if errors.As(int_err, &unmarshalErr){
_128 errorResponse(w, "Bad request. Wrong type provided for field " + unmarshalErr.Value + unmarshalErr.Field + unmarshalErr.Struct, http.StatusBadRequest)
_128 errorResponse(w, "Bad request.", http.StatusBadRequest)
_128 generateRtcToken(int_uid, channel_name, role)
_128 errorResponse(w, rtc_token, http.StatusOK)
_128 func errorResponse(w http.ResponseWriter, message string, httpStatusCode int){
_128 w.Header().Set("Content-Type", "application/json")
_128 w.Header().Set("Access-Control-Allow-Origin", "*")
_128 w.WriteHeader(httpStatusCode)
_128 resp := make(map[string]string)
_128 resp["token"] = message
_128 resp["code"] = strconv.Itoa(httpStatusCode)
_128 jsonResp, _ := json.Marshal(resp)
_128 // Video Calling token from Video SDK num uid
_128 http.HandleFunc("/fetch_rtc_token", rtcTokenHandler)
_128 fmt.Printf("Starting server at port 8082\n")
_128 if err := http.ListenAndServe(":8082", nil); err != nil {
-
A go.mod
file defines this module’s import path and dependency requirements. To create the go.mod
for your token server, run the following command:
_1$ go mod init sampleServer
-
Get dependencies by running the following command:
-
Start the server by running the following command:
This section uses the Web client as an example to show how to use a token for client-side user authentication.
In order to show the authentication workflow, this section shows how to build and run a Web client on your local machine.
This sample client is for demonstration purposes only. Do not use it in a production environment.
-
Create the project structure of the Web client with a folder including the following files.
index.html
: User interface
client.js
: App logic with Agora Video Calling Web SDK 4.x
-
In index.html
, add the following code to include the app logic in the UI:
_13 <title>Token demo</title>
_13<script src="https://unpkg.com/axios/dist/axios.min.js"></script>
_13 <script src="https://download.agora.io/sdk/release/AgoraRTC_N.js"></script>
_13 <script src="./client.js"></script>
-
Create the app logic by editing client.js
with the following content. Then replace <Your App ID>
with your App ID. The App ID must match the one in the server. You also need to replace <Your Host URL and port>
with the host URL and port of the local Golang server you have just deployed, such as 10.53.3.234:8082
.
_105 // For the local audio and video tracks.
_105 localAudioTrack: null,
_105 localVideoTrack: null,
_105 // Pass your app ID here.
_105 appId: "<Your app ID>",
_105 // Set the channel name.
_105 channel: "ChannelA",
_105 // Set the user role in the channel.
_105// Fetch a token from the Golang server.
_105function fetchToken(uid, channelName, tokenRole) {
_105 return new Promise(function (resolve) {
_105 axios.post('http://<Your Host URL and port>/fetch_rtc_token', {
_105 channelName: channelName,
_105 'Content-Type': 'application/json; charset=UTF-8'
_105 .then(function (response) {
_105 const token = response.data.token;
_105 .catch(function (error) {
_105async function startBasicCall() {
_105 const client = AgoraRTC.createClient({ mode: "live", codec: "vp8" });
_105 client.setClientRole(options.role);
_105 // Fetch a token before calling join to join a channel.
_105 let token = await fetchToken(uid, options.channel, 1);
_105 await client.join(options.appId, options.channel, token, uid);
_105 rtc.localAudioTrack = await AgoraRTC.createMicrophoneAudioTrack();
_105 rtc.localVideoTrack = await AgoraRTC.createCameraVideoTrack();
_105 await client.publish([rtc.localAudioTrack, rtc.localVideoTrack]);
_105 const localPlayerContainer = document.createElement("div");
_105 localPlayerContainer.id = uid;
_105 localPlayerContainer.style.width = "640px";
_105 localPlayerContainer.style.height = "480px";
_105 document.body.append(localPlayerContainer);
_105 rtc.localVideoTrack.play(localPlayerContainer);
_105 console.log("publish success!");
_105 client.on("user-published", async (user, mediaType) => {
_105 await client.subscribe(user, mediaType);
_105 console.log("subscribe success");
_105 if (mediaType === "video") {
_105 const remoteVideoTrack = user.videoTrack;
_105 const remotePlayerContainer = document.createElement("div");
_105 remotePlayerContainer.textContent = "Remote user " + user.uid.toString();
_105 remotePlayerContainer.style.width = "640px";
_105 remotePlayerContainer.style.height = "480px";
_105 document.body.append(remotePlayerContainer);
_105 remoteVideoTrack.play(remotePlayerContainer);
_105 if (mediaType === "audio") {
_105 const remoteAudioTrack = user.audioTrack;
_105 remoteAudioTrack.play();
_105 client.on("user-unpublished", user => {
_105 const remotePlayerContainer = document.getElementById(user.uid);
_105 remotePlayerContainer.remove();
_105 // When token-privilege-will-expire occurs, fetch a new token from the server and call renewToken to renew the token.
_105 client.on("token-privilege-will-expire", async function () {
_105 let token = await fetchToken(uid, options.channel, 1);
_105 await client.renewToken(token);
_105 // When token-privilege-did-expire occurs, fetch a new token from the server and call join to rejoin the channel.
_105 client.on("token-privilege-did-expire", async function () {
_105 console.log("Fetching the new Token")
_105 let token = await fetchToken(uid, options.channel, 1);
_105 console.log("Rejoining the channel with new Token")
_105 await client.join(options.appId, options.channel, token, uid);
In the code example, you can see that token is related to the following code logic in the client:
- Call
join
to join the channel with token, uid, and channel name. The uid and channel name must be the same as the ones used to generate the token.
- The
token-privilege-will-expire
callback occurs 30 seconds before a token expires. When the token-privilege-will-expire
callback is triggered,the client must fetch the token from the server and call renewToken
to pass the new token to the SDK.
- The
token-privilege-did-expire
callback occurs when a token expires. When the token-privilege-did-expire
callback is triggered, the client must fetch the token from the server and call join
to use the new token to join the channel.
-
Open index.html
with a supported browser to perform the following actions:
- Successfully joining a channel.
- Renewing a token every 10 seconds.
This section introduces token generator libraries, version requirements, and related documents about tokens.
Agora provides an open-source AgoraDynamicKey repository on GitHub, which enables you to generate tokens on your server with programming languages such as C++, Java, and Go.
This section introduces the parameters and descriptions for the method to generate a token. Take C++ as an example:
_7static std::string buildTokenWithUid(
_7 const std::string& appId,
_7 const std::string& appCertificate,
_7 const std::string& channelName,
_7 uint32_t privilegeExpiredTs = 0);
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: - All lowercase English letters: a to z.
- All upper English letters: A to Z.
- All numeric characters: 0 to 9.
- The space character.
- Punctuation characters and other symbols, including: "!", "#", "$", "%", "&", "(", ")", "+", "-", ":", ";", "<", "=", ".", ">", "?", "@", "[", "]", "^", "_", " , ", "|", "~", ",".
|
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. Role_Publisher(1) : (Default) The user has the privilege of a publisher, that is, the user can publish streams in the channel.Role_Subscriber(2) : The user has the privilege of a subscriber, that is, the user can only subscribe to streams, not publish them, in the channel. This value takes effect only if you have enabled co-host authentication. For details, see FAQ How do I use co-host authentication. |
privilegeExpiredTs | The Unix timestamp (s) when the token expires, represented by the sum of the current timestamp and the valid time of the token. For example, if you set privilegeExpiredTs as the current timestamp plus 600 seconds, the token expires in 10 minutes. A token is valid for 24 hours at most. If you set this parameter as 0 or a period longer than 24 hours, the token is still valid for 24 hours. |
-
Replace the rtctokenbuilder
import statement, and remove the "time"
import statement:
_13 // rtctokenbuilder "github.com/AgoraIO/Tools/DynamicKey/AgoraDynamicKey/go/src/RtcTokenBuilder"
_13 rtctokenbuilder "github.com/AgoraIO/Tools/DynamicKey/AgoraDynamicKey/go/src/rtctokenbuilder2"
-
Remove the timestamp generation statements. Add tokenExpireTimeInSeconds
and privilegeExpireTimeInSeconds
:
_7// expireTimeInSeconds := uint32(40)
_7// Gets current timestamp.
_7// currentTimestamp := uint32(time.Now().UTC().Unix())
_7// Timestamp when the token expires.
_7// expireTimestamp := currentTimestamp + expireTimeInSeconds
_7tokenExpireTimeInSeconds := uint32(40)
_7privilegeExpireTimeInSeconds := uint32(40)
-
Update the token builder function:
_6// result, err := rtctokenbuilder.BuildTokenWithUID(appID, appCertificate, channelName, int_uid, role, expireTimestamp)
_6// Update BuildTokenWithUID with BuildTokenWithUid
_6// Update expireTimestamp with tokenExpireTimeInSeconds and privilegeExpireTimeInSeconds
_6result, err := rtctokenbuilder.BuildTokenWithUid(appID, appCertificate, channelName, int_uid, role, tokenExpireTimeInSeconds, privilegeExpireTimeInSeconds)
-
Remove unsupported roles:
_14 // DEPRECATED. RoleAttendee has the same privileges as RolePublisher.
_14 // role = rtctokenbuilder.RoleAttendee
_14 role = rtctokenbuilder.RolePublisher
_14 role = rtctokenbuilder.RoleSubscriber
_14 // DEPRECATED. RoleAdmin has the same privileges as RolePublisher.
_14 // role = rtctokenbuilder.RoleAdmin
The client does not need any updates as long as the Video Calling Web SDK used in the Web client is v4.8.0 or later. For more information about the SDK versions that support AccessToken2, see
SDK compatibility for AccessToken2.
In the index.html
file, make the following changes:
_14 <title>Token demo</title>
_14<script src="https://unpkg.com/axios/dist/axios.min.js"></script>
_14 <!-- <script src="https://download.agora.io/sdk/release/AgoraRTC_N.js"></script>-->
_14 <!-- Upgrade SDK to support AccessToken2.-->
_14 <script src="https://download.agora.io/sdk/release/AgoraRTC_N-4.8.0.js"></script>
_14 <script src="./client.js"></script>
If you are also using other Video SDK related products or services such as Cloud Recording and streaming, Agora recommends you contact the Agora technical support team before upgrading to AccessToken2.
To test the AccessToken2 server, open index.html
with a supported browser to perform the following actions:
- Successfully joining a channel.
- Renewing a token every 10 seconds.