Skip to main content
Android
iOS
macOS
Web
Flutter
Linux C++
Unity

Secure authentication with tokens

Authentication is the act of validating the identity of a user before they access a system. Agora uses digital tokens to authenticate users and their privileges before they access Signaling. A token is a string used to verify user privileges when logging in or joining a channel. When a user connects to Agora and passes in the token, the server verifies the user's identity and permissions based on the information in the token.

This page shows you how to set up a token server, and use it to connect securely to Signaling.

Understand the tech

Signaling provides two types of channels:

  • Message channels: To join a message channel, you only need to use an RTM token when calling the login method. An RTM token is valid only for the user Id that you use to generate it.
  • Stream channels: To join a stream channel, you use an RTC token when calling the join method. An RTC token is valid only for the channel name and the user Id that you used to generate it.

The following figure shows the call flow you implement to create step-up-authentication with Signaling:

token authentication flow

To log in to Signaling, your app retrieves an RTM token from the token server in your security infrastructure. Your app then sends this token to Agora SD-RTN™ for authentication. Agora SD-RTN™ validates the token and reads the user and project information stored in the token. To join a stream channel you request an RTC token from the server by supplying a user Id and a channel name. You do not need an authentication token to subscribe to a message channel.

A token contains the following information:

  • The App ID of your Agora project
  • The user Id of the user to be authenticated
  • The stream channel name (RTC token only)
  • The Unix timestamp indicating when the token will expire

Prerequisites

Ensure that you have:

  • Integrated the Signaling SDK in your project, and implemented the framework functionality from the SDK quickstart page.

  • The following information from Agora Console:

    • App ID: A unique string provided by Agora that identifies your project.
    • App certificate: A string generated using Agora Console to enable token authentication. To obtain the App certificate for your project, enable primary certificate.

Implement basic authentication

In the SDK quickstart, the app uses an authentication token obtained from Agora Console to join a channel. In a production environment, your app retrieves this token from a token server.

Token generation code

Agora provides an open source token generator code repository on GitHub. The repository contains code samples, based on the HMAC-SHA256 algorithm, in the following languages ​​to generate tokens on your own server:

LanguageCore methodSample code
GobuildTokensample.go
PHPbuildTokenRtmTokenBuilder2Sample.php
Python 2buildTokenRtmTokenBuilder2Sample.py
Python 3buildTokenRtmTokenBuilder2Sample.py
C++buildTokenRtmTokenBuilder2Sample.cpp
JavabuildTokenRtmTokenBuilder2Sample.java

Generate a token

This section shows you how to generate an RTM token using Go language AccessToken2 code from the GitHub repository. To use another language refer to the code samples and READMEs in the Github repository. To generate an RTC token refer to Generate an RTC token.

Before proceeding, make sure that you have:

  • Installed Go 1.14 or above
  • If you are using a Go version lower than 1.16, set the GO111MODULE environment variable to on.

Take the following steps to set up a token generation server:

  1. Create a server.go file containing the following code. Replace Your_App_ID and Your_App_Certificate with your app ID and app certificate from Agora Console.


    _104
    package main
    _104
    _104
    import (
    _104
    rtmtokenbuilder "github.com/AgoraIO/Tools/DynamicKey/AgoraDynamicKey/go/src/rtmtokenbuilder2"
    _104
    "fmt"
    _104
    "log"
    _104
    "net/http"
    _104
    "time"
    _104
    "encoding/json"
    _104
    "errors"
    _104
    "strconv"
    _104
    )
    _104
    _104
    type rtm_token_struct struct{
    _104
    Uid_rtm string `json:"uid"`
    _104
    }
    _104
    _104
    var rtm_token string
    _104
    var rtm_uid string
    _104
    _104
    // Use RtmTokenBuilder to generate an RTM Token
    _104
    func generateRtmToken(rtm_uid string){
    _104
    _104
    appID := "Your_App_ID"
    _104
    appCertificate := "Your_App_Certificate"
    _104
    // Token expiration time in seconds
    _104
    expireTimeInSeconds := uint32(3600)
    _104
    currentTimestamp := uint32(time.Now().UTC().Unix())
    _104
    expireTimestamp := currentTimestamp + expireTimeInSeconds
    _104
    _104
    result, err := rtmtokenbuilder.BuildToken(appID, appCertificate, rtm_uid, expireTimestamp)
    _104
    if err != nil {
    _104
    fmt.Println(err)
    _104
    } else {
    _104
    fmt.Printf("Rtm Token: %s\n", result)
    _104
    _104
    rtm_token = result
    _104
    _104
    }
    _104
    }
    _104
    _104
    func rtmTokenHandler(w http.ResponseWriter, r *http.Request){
    _104
    w.Header().Set("Content-Type", "application/json;charset=UTF-8")
    _104
    w.Header().Set("Access-Control-Allow-Origin", "*")
    _104
    w.Header().Set("Access-Control-Allow-Methods", "POST, OPTIONS");
    _104
    w.Header().Set("Access-Control-Allow-Headers", "*");
    _104
    _104
    if r.Method == "OPTIONS" {
    _104
    w.WriteHeader(http.StatusOK)
    _104
    return
    _104
    }
    _104
    _104
    if r.Method != "POST" && r.Method != "OPTIONS" {
    _104
    http.Error(w, "Unsupported method. Please check.", http.StatusNotFound)
    _104
    return
    _104
    }
    _104
    _104
    _104
    var t_rtm_str rtm_token_struct
    _104
    var unmarshalErr *json.UnmarshalTypeError
    _104
    str_decoder := json.NewDecoder(r.Body)
    _104
    rtm_err := str_decoder.Decode(&t_rtm_str)
    _104
    _104
    if (rtm_err == nil) {
    _104
    rtm_uid = t_rtm_str.Uid_rtm
    _104
    }
    _104
    _104
    if (rtm_err != nil) {
    _104
    if errors.As(rtm_err, &unmarshalErr){
    _104
    errorResponse(w, "Bad request. Please check your params.", http.StatusBadRequest)
    _104
    } else {
    _104
    errorResponse(w, "Bad request.", http.StatusBadRequest)
    _104
    }
    _104
    return
    _104
    }
    _104
    _104
    generateRtmToken(rtm_uid)
    _104
    errorResponse(w, rtm_token, http.StatusOK)
    _104
    log.Println(w, r)
    _104
    }
    _104
    _104
    _104
    func errorResponse(w http.ResponseWriter, message string, httpStatusCode int){
    _104
    w.Header().Set("Content-Type", "application/json")
    _104
    w.Header().Set("Access-Control-Allow-Origin", "*")
    _104
    w.WriteHeader(httpStatusCode)
    _104
    resp := make(map[string]string)
    _104
    resp["token"] = message
    _104
    resp["code"] = strconv.Itoa(httpStatusCode)
    _104
    jsonResp, _ := json.Marshal(resp)
    _104
    w.Write(jsonResp)
    _104
    _104
    }
    _104
    _104
    func main(){
    _104
    // Use an int type uid to generate an RTM Token
    _104
    http.HandleFunc("/fetch_rtm_token", rtmTokenHandler)
    _104
    _104
    fmt.Printf("Starting server at port 8082\n")
    _104
    _104
    if err := http.ListenAndServe(":8082", nil); err != nil {
    _104
    log.Fatal(err)
    _104
    }
    _104
    }

    Refer to the BuildToken API reference for parameter descriptions.

  2. The go.mod file defines the import paths and dependencies. To create this file for your token server, run the following command:


    _1
    go mod init sampleServer

  3. To install the dependencies, run the following command:


    _1
    go get

  4. To start the server, execute:


    _1
    go run server.go

Important

This sample server is for development purposes only. It should not be used in a production environment.

Login with a token

To log in to Signaling using an RTM token, fetch a token from your token server and pass it to the SDK by calling login:


_14
// Fetch a token from your token server
_14
_14
// Log in to Signaling
_14
rtmClient.login("your_token", new ResultCallback<Void>() {
_14
@Override
_14
public void onSuccess(Void responseInfo) {
_14
// Handle login success
_14
}
_14
_14
@Override
_14
public void onFailure(ErrorInfo errorInfo) {
_14
// Handle errors
_14
}
_14
});

Note
  • The user ID and app ID you use to initialize the Signaling client instance must be the same as the user ID and app ID you use on the token server to generate a token.
  • When integrating the Signaling SDK into your app, ensure that the app certificate is properly configured. The app certificate serves as a key authentication mechanism between your app and Agora SD-RTN™ to ensure secure and reliable communication.

Join a stream channel using a token

To join a stream channel using a token, fetch an RTC token from your token server and pass it to the SDK when you call join. For details, refer to the API reference.

Token expiration and renewal

You configure the validity period of an RTM token in your token generator according to your business needs. The maximum validity period of a token is 24 hours. When an RTM token is about to expire, the onTokenPrivilegeWillExpire callback is triggered 30 seconds before the expiration time. When you receive this callback, retrieve a fresh RTM token from your token server, and call renewToken to pass the new token to the SDK.

If the token expires, the SDK triggers an onLinkStateEvent callback and reports the following information:

  • currentState: FAILED
  • operation: SERVER_REJECT
  • reason: Ticket expired

In this scenario, log out of Signaling using the logout method, retrieve a fresh token, and login again.

info

An alternative approach to handling token expiration through the onTokenPrivilegeWillExpire and onLinkStateEvent callbacks is to handle expiration proactively. Best practice is to update the token periodically to ensure seamless authentication and uninterrupted operation.

Reference

This section contains content that completes the information on this page, or points you to documentation that explains other aspects to this product.

BuildToken API reference

This section explains the API parameters and descriptions for generating AccessToken2 using Golang as an example:


_9
func BuildToken(appId string, appCertificate string, userId string, expire uint32) (string, error) {
_9
token := accesstoken.NewAccessToken(appId, appCertificate, expire)
_9
_9
serviceRtm := accesstoken.NewServiceRtm(userId)
_9
serviceRtm.AddPrivilege(accesstoken.PrivilegeLogin, expire)
_9
token.AddService(serviceRtm)
_9
_9
return token.Build()
_9
}

ParameterDescription
appIdThe app ID generated when you create a project in Agora Console.
appCertificateYour app certificate.
userIdThe user ID, used to identify a user or device. To differentiate between users and devices, ensure that the userId is globally unique and remains unchanged for the lifetime of the user or device.
expireThe validity period of the token (in seconds). The maximum validity period is 24 hours.

Signaling