Skip to main content

Secure authentication with tokens

Authentication is the act of validating the identity of each user before they access a system. Agora uses digital tokens to authenticate users and their privileges before they access Agora SD-RTN™ to join Voice Calling. Each token is valid for a limited period and works only for a specific channel. For example, you cannot use the token generated for a channel called AgoraChannel to join the AppTest channel.

This page shows you how to quickly set up an authentication token server, retrieve a token from the server, and use it to connect securely to a specific Voice Calling channel.

Understand the tech

An authentication token is a dynamic key that is valid for a maximum of 24 hours. On request, a token server returns an authentication token that is valid to join a specific channel.

When users attempt to connect to an Agora channel from your app, your app retrieves a 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. A token contains the following information:

  • The App ID of your Agora project

  • The App certificate of your Agora project

  • The channel name

  • The user ID of the user to be authenticated (optional)

  • The privilege of the user, either as a publisher or a subscriber

  • The Unix timestamp showing when the token will expire

The following figure shows the call flow you need to implement to create step-up-authentication with Agora Voice Calling:

token authentication flow

Prerequisites

To follow this procedure you must have:

  • Implemented the Quickstart
  • Created a Railway account and get it verified by your github account
  • If you want to integrate a token generator directly into your security infrastructure, see Token generators.
  • Android Studio 4.1 or higher.
  • Android SDK API Level 24 or higher.
  • A mobile device that runs Android 4.1 or higher.
  • An Agora account and project.

  • A computer with Internet access.

    Ensure that no firewall is blocking your network communication.

Project setup

To integrate token authentication into your app, do the following:

  1. Open the project you created in the Quickstart.

  2. Log in to your Railway account.

Implement the authentication workflow

In the SDK quickstart project you implemented, your app uses an authentication token obtained manually from Agora Console to join a channel. In a production environment, your app retrieves this token from a token server. This section shows you how to:

  1. Create and run a token server

  2. Retrieve and use tokens from a token server

Create and run a token server

This section shows you how to deploy a token server on Railway.

  1. Click here and deploy a token server to Railway.

    Railway retrieves the project code and necessary files from Github and takes you to the Deploy Agora Token Deployment page. On this page, fill in the following information:

    1. Github account: The GitHub account where Railway should clone the token deployment repository.

    2. Repository name: Name of the cloned repository, by default set to agora-token-service.

    3. Private repository: Tick this option if you don't want the cloned repository to be seen on your public github profile.

    4. APP_CERTIFICATE: The obtained from Agora Console.

    5. APP_ID: The App ID obtained from Agora Console.

  2. Click Deploy. Railway configures and builds the token server.

    You will see the deployment turn green once it is complete.

  3. Click the URL.

    Railway opens the token server URL in your browser. The URL is of the form agora-token-service-production-<id>.up.railway.app where <id> is a random alphanumeric string.

    Don’t worry if you see 404 page not found in your browser. Follow the next steps and test your server.

  4. Test your server

    1. Retrieve a token

      To retrieve an Video SDK token, send a request to the token server using a URL based on the Token server GET request structure:


      _1
      /rtc/:channelName/:role/:tokentype/:uid/?expiry=expireTime

      For example: https://agora-token-service-production-92ff.up.railway.app/rtc/MyChannel/1/uid/1/?expiry=300

      Your token server returns the following JSON object to your browser:


      _1
      {"rtcToken":"ThisIsAnExampleTokenThisIsAnExampleTokenThisIsAnExampleTokenThisIsAnExampleTokenThisIsAnExampleToken"}

To see how to create a token generator inside your IAM system, see Integrate a token generator.

Retrieve and use tokens from a token server

To integrate authentication into your app:

  1. Add the necessary dependencies

    In order to make HTTPS calls to a token server and interpret the JSON return parameters, integrate the OkHttp client and Gson library into your Android project. In /Gradle Scripts/build.gradle (Module: <projectname>.app), add the following lines under dependencies.


    _8
    ...
    _8
    dependencies
    _8
    {
    _8
    ...
    _8
    implementation 'com.squareup.okhttp3:okhttp:4.9.3'
    _8
    implementation 'com.google.code.gson:gson:2.9.0'
    _8
    ...
    _8
    }

  2. Allow cleartext network traffic

    Add the following line in /app/Manifests/AndroidManifest.xml, under <application:


    _1
    android:usesCleartextTraffic = "true"

  3. Enable the user to specify a channel

    Add a text box to the user interface. In /app/res/layout/activity_main.xml add the following lines before </RelativeLayout>:


    _10
    <EditText
    _10
    android:id="@+id/editChannelName"
    _10
    android:layout_width="match_parent"
    _10
    android:layout_height="wrap_content"
    _10
    android:layout_below="@id/JoinButton"
    _10
    android:layout_alignStart="@id/JoinButton"
    _10
    android:layout_alignEnd="@id/LeaveButton"
    _10
    android:hint="Type the channel name here"
    _10
    android:inputType="text"
    _10
    android:text="" />

  4. Add the required import statements

    In /app/java/com.example.<projectname>/MainActivity, add the following lines after the last import statement:


    _13
    import android.util.Log;
    _13
    import android.widget.EditText;
    _13
    _13
    import okhttp3.OkHttpClient;
    _13
    import okhttp3.Request;
    _13
    import okhttp3.Response;
    _13
    import okhttp3.Call;
    _13
    import okhttp3.Callback;
    _13
    _13
    import com.google.gson.Gson;
    _13
    _13
    import java.io.IOException;
    _13
    import java.util.Map;

  5. Add variables for your connection to the token server

    Declare the variables you need to specify the user id, token role, token server URL and the token expire time. Add the following declarations to class MainActivity after private RtcEngine agoraEngine;


    _4
    private int tokenRole; // The token role
    _4
    private String serverUrl = "<Token Server URL>"; // The base URL to your token server, for example, "https://agora-token-service-production-92ff.up.railway.app".
    _4
    private int tokenExpireTime = 40; // Expire time in Seconds.
    _4
    private EditText editChannelName; // To read the channel name from the UI.

    Make sure you specify the token server URL in exactly the same format as shown in the example.

  6. Set up access to the channel name text box from code

    Add the following line at the end of the onCreate method,.


    _1
    editChannelName = (EditText) findViewById(R.id.editChannelName);

  7. Retrieve a token from the server

    Use a GET request to retrieve an authentication token for a specific channel from the token server, then decode the return parameters.

    In the MainActivity class, add the following fetchToken method:


    _35
    // Fetch the <Vg k="VSDK" /> token
    _35
    private void fetchToken(int uid, String channelName, int tokenRole) {
    _35
    // Prepare the Url
    _35
    String URLString = serverUrl + "/rtc/" + channelName + "/" + tokenRole + "/"
    _35
    + "uid" + "/" + uid + "/?expiry=" + tokenExpireTime;
    _35
    _35
    OkHttpClient client = new OkHttpClient();
    _35
    _35
    // Instantiate the RequestQueue.
    _35
    Request request = new Request.Builder()
    _35
    .url(URLString)
    _35
    .header("Content-Type", "application/json; charset=UTF-8")
    _35
    .get()
    _35
    .build();
    _35
    Call call = client.newCall(request);
    _35
    call.enqueue(new Callback() {
    _35
    _35
    @Override
    _35
    public void onFailure(Call call, IOException e) {
    _35
    Log.e("IOException", e.toString());
    _35
    }
    _35
    _35
    @Override
    _35
    public void onResponse(Call call, Response response) throws IOException {
    _35
    if (response.isSuccessful()) {
    _35
    Gson gson = new Gson();
    _35
    String result = response.body().string();
    _35
    Map map = gson.fromJson(result, Map.class);
    _35
    String _token = map.get("rtcToken").toString();
    _35
    if (isJoined) setToken(_token);
    _35
    Log.i("Token Received", token);
    _35
    }
    _35
    }
    _35
    });
    _35
    }

  8. Join a channel using the token

    Use the retrieved token to either join a channel or to renew an expiring token.

    In the MainActivity class, add the following setToken method:


    _19
    void setToken(String newValue) {
    _19
    token = newValue;
    _19
    if (!isJoined) { // Join a channel
    _19
    ChannelMediaOptions options = new ChannelMediaOptions();
    _19
    _19
    // For a Video call, set the channel profile as COMMUNICATION.
    _19
    options.channelProfile = Constants.CHANNEL_PROFILE_COMMUNICATION;
    _19
    // Set the client role as BROADCASTER or AUDIENCE according to the scenario.
    _19
    options.clientRoleType = Constants.CLIENT_ROLE_BROADCASTER;
    _19
    // Start local preview.
    _19
    agoraEngine.startPreview();
    _19
    _19
    // Join the channel with a token.
    _19
    agoraEngine.joinChannel(token, channelName, uid, options);
    _19
    } else { // Already joined, renew the token by calling renewToken
    _19
    agoraEngine.renewToken(token);
    _19
    showMessage("Token renewed");
    _19
    }
    _19
    }

  9. Handle the event triggered by Agora SD-RTN™ when the token is about to expire

    A token expires after the expireTime specified in the call to the token server or expires after 24 hours, if the time is not specified. The onTokenPrivilegeWillExpire event receives a callback when the current token is about to expire so that a fresh token may be retrieved and used.

    In the MainActivity class, add the following method after private final IRtcEngineEventHandler mRtcEventHandler = new IRtcEngineEventHandler() {


    _7
    // Listen for the event that the token is about to expire
    _7
    @Override
    _7
    public void onTokenPrivilegeWillExpire(String token) {
    _7
    Log.i("i", "Token Will expire");
    _7
    fetchToken(uid, channelName, tokenRole);
    _7
    super.onTokenPrivilegeWillExpire(token);
    _7
    }

  10. Update the joinChannel method to fetch a token

    In the MainActivity class, replace the joinChannel method with the following:


    _20
    public void joinChannel(View view) {
    _20
    channelName = editChannelName.getText().toString();
    _20
    if (channelName.length() == 0) {
    _20
    showMessage("Type a channel name");
    _20
    return;
    _20
    } else if (!serverUrl.contains("http")) {
    _20
    showMessage("Invalid token server URL");
    _20
    return;
    _20
    }
    _20
    _20
    if (checkSelfPermission()) {
    _20
    tokenRole = Constants.CLIENT_ROLE_BROADCASTER;
    _20
    // Display LocalSurfaceView.
    _20
    setupLocalVideo();
    _20
    localSurfaceView.setVisibility(View.VISIBLE);
    _20
    fetchToken(uid, channelName, tokenRole);
    _20
    } else {
    _20
    showMessage("Permissions was not granted");
    _20
    }
    _20
    }

  1. Enable the user to specify a channel

    Add a text box to the user interface.

    1. In your Android project, right-click Canvas, then click UI > InputField. A text box appears in the scene Canvas.

    2. In Inspector, rename InputField to "textbox", then change Pos Y to 30.

    3. Select the Placeholder sub-item of textbox, in Inspector, change Text to "Channel name".

  2. Add the required import statements

    In Project, open Assets/Agora-RTC-Plugin/Agora-Unity-RTC-SDK/Code/NewBehaviourScript.cs, then add the following lines before using agora_gaming_rtc;:


    _2
    using UnityEngine.Networking;
    _2
    using System;

  3. Add variables for your connection to the token server

    Declare the variables you need to specify the user id, token-server URL and the token expire time. In your script file, add the following declarations in NewBehaviourScript:


    _3
    private string serverUrl = ""; // The base URL to your token server. For example, https://agora-token-service-production-92ff.up.railway.app"
    _3
    private int ExpireTime; //Expire time in Seconds.
    _3
    private string uid = "0"; // An integer that identifies the user.

  4. Retrieve a token from the server

    Use a GET request to retrieve an authentication token for a specific channel from the token server. In your script file, add the following code before Start:

  5. Add a class to extract the token from a JSON object

    In your script file, add the following class before public class NewBehaviourScript : MonoBehaviour:


    _4
    public class TokenObject
    _4
    {
    _4
    public string rtcToken;
    _4
    }

  6. Handle the event triggered by Agora SD-RTN™ when the token is about to expire

    A token expires after the ExpireTime specified in the call to the token server or after 24 hours, if the time is not specified. The OnTokenPrivilegeWillExpire is triggered when the current token is about to expire so that a fresh token may be retrieved and used.

    i. In your script file, add the following code before Join method:


    _13
    void OnTokenPrivilegeWillExpireHandler(string token)
    _13
    {
    _13
    // Call a method to fetch the token, with a callback to FetchRenew
    _13
    StartCoroutine(FetchToken(serverUrl, CHANNEL , uid, ExpireTime, this.FetchRenew));
    _13
    Debug.Log("Token Expired");
    _13
    }
    _13
    void FetchRenew(string newToken)
    _13
    {
    _13
    // Update <Vg k="VSDK" /> Engine with new token, which will not expire so soon
    _13
    mRtcEngine.RenewToken(newToken);
    _13
    TOKEN = newToken;
    _13
    Debug.Log(TOKEN);
    _13
    }

    ii. In your script file, locate SetupVideoSDKEngine and add the following line before mRtcEngine.OnUserOffline = OnUserOffline;:


    _1
    mRtcEngine.OnTokenPrivilegeWillExpire += OnTokenPrivilegeWillExpireHandler;

  7. Update the Join method to fetch a token

    Use FetchToken to retrieve a fresh token from server before joining a channel. In your script file, add the following code before mRtcEngine.EnableVideo();:


    _7
    CHANNEL = GameObject.Find("textbox").GetComponent<InputField>().text;
    _7
    if (CHANNEL == "")
    _7
    {
    _7
    Debug.Log("Channel name is required!");
    _7
    return;
    _7
    }
    _7
    StartCoroutine(FetchToken(serverUrl, CHANNEL , uid, ExpireTime, this.FetchRenew));

Test your implementation

To ensure that you have implemented Agora token authentication workflow in your app:

  1. Generate a token in Agora Console.

    Users communicate securely using channels in the same project. The App ID you use to generate this token must be the same one you supplied to Railway.

  2. In your browser, navigate to the Agora web demo and update App ID, Channel, and Token with the values for your temporary token, then click Join.

    1. Set the variables in your app:

      1. Update appID in the declarations to the value from Agora Console.

      2. Set token to an empty string in the declarations.

      3. Update serverUrl in the declarations to the base address of your token server, for example, https://agora-token-service-production-92ff.up.railway.app.

      4. If you are developing with UI Kit: set channelName to the same Channel you specified in the web demo app.

    2. Connect a physical Android device to your development device.

    3. In Android Studio, click Run app. A moment later you see the project installed on your device.

      If this is the first time you run the project, grant microphone and camera access to your app.

    4. If you are developing with Voice SDK: enter the same channel name in the UI text box that you used to connect to the Agora web demo.

    5. Click Join to connect your Android app to the web demo app.

Your app magically connects to the same channel you used in web demo. You don’t need to hardcode a token in your app; each channel is secured with a specific token, and each token is refreshed automatically. That’s pretty cool!

Reference

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

Source code for a token server

The token server RESTful web service used in this page is written in Golang using the Gin framework. Want to use the code in your authentication service? Download the token server source code and binaries for various platforms from Github.

To see how to create a token generator inside your IAM system, see Integrate a token generator.

Token server GET request structure

A token server GET request has the following structure:


_1
/rtc/:channelName/:role/:tokentype/:uid/?expiry=expireTime

  • :channelName is the name of the Agora Channel you wish to join

    A channel name may contain numbers with both upper and lower case letters. The name length must be less than 64 characters.

  • :role is the user role

    Use publisher for publisher, subscriber for subscriber.

  • :tokentype is the type of token

    Agora SD-RTN™ supports both integer user IDs and string user accounts for token generation. To ensure smooth communication, all the users in a channel must use the same type of ID, that is, either the integer uid, or a string userAccount. Best practice is to use the uid.

  • :uid is the user ID

    User Id can be any 32-bit unsigned integer. It can be set to 0, if you do not need to authenticate the user based on the user ID.

  • expireTime (optional) is the number of seconds after which the token will expire

    By default, a token expires after 24 hours unless a shorter life span is explicitly specified in the token request.

Voice Calling