Skip to main content

You are viewing Agora Docs forBeta products and features. Switch to Docs

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 Signaling. Each token is valid for a limited period and works for a specific UID only. For example, you cannot use a token generated for UID john for UID doe.

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 Signaling as a specific user. You use this server for development purposes. To see how to develop your own token generator and integrate it into your production IAM system, read Token generators.

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 for a specific user. A token server generates two types of tokens:

  • To initialize the Signaling Engine, you use an RTM token. An RTM token is valid only for the user Id that you use to generate it.
  • To join a stream channel, you use an RTC token. An RTC token is valid only for the channel name and the user Id that you use to generate it.

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

token authentication flow

To initiate the Signaling engine, 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 App certificate of your Agora project

  • The User Id of the user to be authenticated

  • The Unix timestamp showing when the token will expire

  • The channel name (only for RTC tokens)

When the token is about to expire, Agora SD-RTN™ sends an event to your app and you renew the session with a new token.

Prerequisites

To follow this page, you must have:

To integrate a token generator directly into your security infrastructure, see Token generators.

Implement the authentication workflow

In the SDK quickstart, the app uses an authentication token obtained manually 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 a cloud platform.

  1. To start deploying the token server to your cloud platform, choose one of the following links:

    The cloud platform retrieves the project code and necessary files from Github, then takes you to the Deployment page.

  2. Fill in the information needed by your cloud platform:

    1. Blueprint name: A unique name for your deployment.

    2. Branch name: The branch of the repo or fork you want to deploy, default is main.

    3. APP_CERTIFICATE: The App Certificate obtained from Agora Console.

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

    5. Github account: The GitHub account where the cloud platform should clone the token server repository.

    6. Repository name: The name of the cloned repository, the default is agora-token-service.

    7. Private repository: Select this option to hide this repository.

  3. Click Deploy. The platform configures and builds the token server.

  4. Click the URL.

    You are notified of a URL where your server is deployed. Click the link and open the token server in your browser. Don’t worry if you see 404 page not found in your browser. Follow the next steps and test your server.

  5. Test your server

    To retrieve a 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-1234.up.railway.app/rtc/MyChannel/1/uid/1/?expiry=300

    Your token server returns a JSON object containing an encrypted token:


    _1
    {"rtcToken":"ThisIsAnExampleTokenThisIsAnExampleTokenThisIsAnExampleTokenThisIsAnExampleTokenThisIsAnExampleToken"}

Authenticate your Signaling session

In Signaling, each authentication token you create is specific for a user ID in your app. You create a token for each user who logs in to Signaling. When you initiate the Signaling Engine, ensure that the UID is the same one you used to create the token.

In order to make HTTPS calls to a token server and interpret the JSON return parameters, the axios HTTP client is integrated into the reference .

To retrieve tokens from the token server and use them to authenticate your app with Signaling using Signaling SDK:

Retrieve an RTM token from the server

Use a GET request to retrieve an RTM authentication token for initializing the Signaling engine.


_51
private fun fetchRTMToken(uid: Int, callback: TokenCallback) {
_51
// Prepare the Url
_51
val urlString = "$serverUrl/rtm/$uid/?expiry=$tokenExpiryTime"
_51
fetchToken(urlString, callback)
_51
}
_51
_51
private fun fetchToken(urlString: String, callback: TokenCallback) {
_51
// Prepare the Url
_51
val client = OkHttpClient()
_51
_51
// Create a request
_51
val request: Request = Builder()
_51
.url(urlString)
_51
.header("Content-Type", "application/json; charset=UTF-8")
_51
.get()
_51
.build()
_51
_51
// Send the async http request
_51
val call = client.newCall(request)
_51
call.enqueue(object : Callback {
_51
// Receive the response in a callback
_51
@Throws(IOException::class)
_51
override fun onResponse(call: Call, response: Response) {
_51
if (response.isSuccessful) {
_51
try {
_51
// Extract token from the response
_51
val responseBody = response.body!!.string()
_51
val jsonObject = JSONObject(responseBody)
_51
val token = if (urlString.contains("/rtm/")) {
_51
// Message channel token
_51
jsonObject.getString("rtmToken")
_51
} else {
_51
// Stream channel token
_51
jsonObject.getString("rtcToken")
_51
}
_51
// Return the token
_51
callback.onTokenReceived(token)
_51
} catch (e: JSONException) {
_51
e.printStackTrace()
_51
callback.onError("Invalid token response")
_51
}
_51
} else {
_51
callback.onError("Token request failed")
_51
}
_51
}
_51
_51
override fun onFailure(call: Call, e: IOException) {
_51
callback.onError("IOException: $e")
_51
}
_51
})
_51
}

Use the token to login into the Signaling Engine

Call fetchToken to get a fresh RTM token. Use the token in the config to initiate the Signaling Engine.


_21
fun loginWithToken(uid: Int): Int {
_21
return if (isValidURL(serverUrl)) { // A valid server url is available
_21
// Fetch a token from the server for the specified uid
_21
fetchRTMToken(uid, object : TokenCallback {
_21
override fun onTokenReceived(token: String?) {
_21
// Use the received token to log in
_21
if (token != null) login(uid, token)
_21
}
_21
_21
override fun onError(errorMessage: String) {
_21
// Handle the error
_21
notify("Error fetching token: $errorMessage")
_21
}
_21
})
_21
0
_21
} else { // use the uid and token from the config.json file
_21
val defaultUid = config!!.optString("uid").toInt()
_21
val token = config!!.optString("token")
_21
login(defaultUid, token)
_21
}
_21
}

Retrieve a Stream Channel token

To join a stream channel you retrieve an RTC token from the token server by specifying the uid and channelName.


_5
fun fetchRTCToken(channelName: String, role: Int, callback: TokenCallback) {
_5
// Fetches the RTC token for stream channels
_5
val urlString = "$serverUrl/rtc/$channelName/$role/uid/$localUid/?expiry=$tokenExpiryTime"
_5
fetchToken(urlString, callback)
_5
}

Use the Stream Channel token to join a stream channel

Create a stream channel using the channel name and call join with the RTC token.


_30
fun joinStreamChannel(channelName: String): Int {
_30
fetchRTCToken(channelName, 1, object : TokenCallback {
_30
override fun onTokenReceived(token: String?) {
_30
// Use the received token to log in
_30
if (token != null) {
_30
streamChannel = signalingEngine!!.createStreamChannel(channelName)
_30
streamChannel.join(
_30
JoinChannelOptions(token, true, true, true),
_30
object : ResultCallback<Void?> {
_30
override fun onFailure(errorInfo: ErrorInfo?) {
_30
notify("Join stream channel failed:\n" + errorInfo.toString())
_30
isStreamChannelJoined = false
_30
}
_30
_30
override fun onSuccess(responseInfo: Void?) {
_30
isStreamChannelJoined = true
_30
mListener?.onSubscribeUnsubscribe(true)
_30
notify("Joined stream channel: $channelName")
_30
}
_30
})
_30
}
_30
}
_30
_30
override fun onError(errorMessage: String) {
_30
// Handle the error
_30
notify("Error fetching token: $errorMessage")
_30
}
_30
})
_30
return 0
_30
}

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

A token expires after the tokenExpiryTime specified in the call to the token server. If the expiry time is not specified the default timeout is 24 hours. The TokenPrivilegeWillExpire event receives a callback when the current token is about to expire so that a fresh token may be retrieved and used.


_4
override fun onTokenPrivilegeWillExpire(token: String) {
_4
handleTokenExpiry()
_4
super.onTokenPrivilegeWillExpire(token)
_4
}

Renew the token

You persist the existing session by retrieving a fresh token and calling renewToken.


_23
protected fun handleTokenExpiry() {
_23
notify("Token is about to expire")
_23
// Fetch a new token
_23
fetchToken(object : TokenCallback {
_23
override fun onTokenReceived(token: String?) {
_23
// Use the token to renew authentication
_23
signalingEngine!!.renewToken(token, object: ResultCallback<Void?> {
_23
override fun onFailure(errorInfo: ErrorInfo?) {
_23
notify("Failed to renew token")
_23
}
_23
_23
override fun onSuccess(responseInfo: Void?) {
_23
notify("Token renewed")
_23
}
_23
})
_23
}
_23
_23
override fun onError(errorMessage: String) {
_23
// Handle the error
_23
notify("Error fetching token: $errorMessage")
_23
}
_23
})
_23
}

Test authentication

To test authentication using a token server:

  1. Configure the project

    1. Setup an Authentication server
    2. Open the file <samples-root>/signaling-manager/src/main/res/raw/config.json

    3. In config.json, set:
      • token to an empty string.
      • serverUrl to the base URL for your token server. For example: https://agora-token-service-production-yay.up.railway.app.
  2. Run the reference app

    1. In Android Studio, connect a physical Android device to your development machine.
    2. Click Run to start the app.
    3. A moment later you see the project installed on your device.
  3. Test server authentication:

    For each user you want to add to the conversation:

    1. Launch an instance of the app.
    2. Enter a numeric user ID, then press Login.
    3. Enter a channel name, then press Subscribe to join a channel.
    4. Send and receive messages between users.

Reference

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

For more information, see:

Signaling