Security within video chat applications is a hot topic at the moment. As remote working and virtual events become more prolific, the need for security will increase.
Within the Agora Platform, one layer of security comes in the form of token authentication. A token, for those of you that don’t know, is a dynamic key that is generated using a set of given inputs. Agora’s Platform uses tokens to authenticate users.
Agora offers token security for both its RTC and RTM SDKs. This guide will explain how to build a simple microservice using Golang and the Gin framework to generate an Agora RTC and RTM tokens.
To start, let’s open our terminal and create a new folder for our project and cd
into it.
mkdir agora-token-server
cd agora-token-server
Now that the project has been created, let’s initialize the project’s Go module.
go mod init agora-token-server
Lastly, we’ll use go get
to add our Gin and Agora dependencies.
go get github.com/gin-gonic/gin
go get github.com/AgoraIO-Community/go-tokenbuilder
Now that the project is set up, open the folder in your favorite code editor and create the main.go
file.
Within the main.go
we’ll start by declaring our package and adding our main
function.
package main
func main() {
}
Next we’ll import the Gin framework, create our Gin app, set up a simple GET
endpoint and set it to listen and serve on localhost
port 8080
. For the simple endpoint, we’ll set it to take the request context and return a JSON response with a 200
status header.
We are ready to test our server. Go back to the terminal window and run:
go run main.go
To test the endpoint open your web browser and visit:
localhost:8080/ping
You’ll see the server respond as expected.
{"message":"pong"}
After we confirm that our endpoint is working, return to the terminal window and use the keyboard command ctrl c
to terminate the process.
Now that we have our Gin server setup, we are ready to add the functionality to generate the RTC and RTM tokens.
Before we can generate our tokens we need to add our AppID
and AppCertificate
. We’ll declare the appID
and appCertificate
as Strings in the global
scope. For this guide, use environment variables to store the project credentials, so we’ll need to retrieve them. Within main()
we’ll use os.LookupEnv
to retrieve the environment variables. The os.LookupEnv
returns a String for the environment variable along with a boolean for whether the variable existed. We’ll use the latter return values to check if the environment is configured correctly. If so we can assign the environment variable values to our global appID
and AppCertificate
variables, respectively.
Next we will add 3 endpoints, one for RTC tokens, another for RTM tokens, and one that returns both tokens.
The RTC token will require a channel name, the UID, the user role, tokentype to distinguish between string and integer based UIDs, and lastly an expiration time. The RTM endpoint only requires a UID and an expiration time. The dual token endpoint will need to accept the same structure as the RTC token endpoint.
api.GET("rtc/:channelName/:role/:tokentype/:uid/", getRtcToken)
api.GET("rtm/:uid/", getRtmToken)
api.GET("rte/:channelName/:role/:tokentype/:uid/", getBothTokens)
To minimize the amount of repeated code, the three functions getRtcToken
, getRtmToken
, and getBothTokens
will call separate functions (parseRtcParams
/parseRtmParams
) to validate and extract the values passed to each endpoint. Then each function will use the returned values to generate the tokens and return them as JSON in the response body
.
RTC tokens can be generated using two types of UIDs (uint
/string
), so we’ll use a function (generateRtcToken
) to wrap the Agora RTC Token Builder functions BuildTokenWithUserAccount
/BuildTokenWithUID
.
Below is the base template for our token server. We’ll walk through each function and fill in the blanks.
We’ll start with getRtcToken
. This function takes a reference to the gin.Context
, using it to call parseRtcParams
which will extract the required values. Then using the returned values to call generateRtcToken
to generate the token String. We’ll also include a few checks for errors to make sure there weren’t any issues along the way. Lastly we’ll build the response.
Next let’s fill in parseRtcParams
. This function also takes a reference to the gin.Context
, which we’ll use to extract the parameters and return them. You’ll notice parseRtcParams
also returns an error
in case we run into any issues we can return an error message.
Lastly, we’ll fill in the generateRtcToken
function. This function takes the channel name, the UID as a string, the type of token (uid
or userAccount
), the role, and the expire time.
Using these values, the function calls the appropriate Agora RTC Token Builder function (BuildTokenWithUserAccount
/BuildTokenWithUID
) to generate a token String. Once the token builder function returns we’ll first check for errors and if there aren’t any we’ll return the token string value.
Next, let’s move on to getRtmToken
. Just like the code above, getRtmToken
takes a reference to the gin.Context
, uses it to call parseRtmParams
to extract the required values, and uses the returned values to generate an RTM token. The difference here is that we call the Agora RTM Token builder directly to generate the token, String. We’ll include the error checks to make sure there weren’t any issues, and lastly we’ll build the response.
Next let’s fill in parseRtmParams
. This function also takes a reference to the gin.Context
, then extracts and returns the parameters.
Now that we are able to generate both RTC and RTM tokens with individual server requests, we are going to fill in getBothTokens
to allow for generating both tokens from a single request. We’ll use code very similar to the getRtcToken
, except this time we’ll include the RTM token.
Let’s go back to our terminal window and run our token server.
run main.go
Once the server instance is running we’ll see the list of endpoints and the message: Listening and serving HTTP on :8080
.
Now that our server instance is running, let’s open our web browser and test. For these tests we’ll try a few variations that omit various query params.
We’ll start with the RTC token:
http://localhost:8080/rtc/testing/publisher/userAccount/1234/
http://localhost:8080/rtc/testing/publisher/uid/1234/
The endpoints will generate a token that can be used in the channel: testing
by a user with the role of publisher
and the UID (String or uint) of 1234
.
{
"rtcToken": "0062ec0d84c41c4442d88ba6f5a2beb828bIADJRwbbO8J93uIDi4J305xNXA0A+pVDTPLPavzwsLW3uAZa8+ij4OObIgDqFTEDoOMyXwQAAQAwoDFfAgAwoDFfAwAwoDFfBAAwoDFf"
}
To test this token we can use the Agora 1:1 Web Demo.
We’ll finish our testing with the Dual token endpoint:
http://localhost:8080/rte/testing/publisher/userAccount/1234/
http://localhost:8080/rte/testing/publisher/uid/1234/
The endpoints will generate both RTC and RTM tokens that can be used by a user with the UID (String or uint) of 1234
and for the Video channel: testing
with the role of publisher
.
{
"rtcToken": "0062ec0d84c41c4442d88ba6f5a2beb828bIAD33wY6pO+xp6iBY8mbYz2YtOIiRoTTrzdIPF9DEFlSIwZa8+ij4OObIgAQ6e0EX+UyXwQAAQDvoTFfAgDvoTFfAwDvoTFfBADvoTFf",
"rtmToken": "0062ec0d84c41c4442d88ba6f5a2beb828bIABbCwQgl2te3rk0MEDZ2xrPoalb37fFhTqmTIbGeWErWaPg45sAAAAAEAD1WwYBX+UyXwEA6APvoTFf"
}
To test the tokens we can use the Agora 1:1 Web Demo for the RTC token and Agora RTM Tutorial Demo for the RTM token.
After testing the endpoints, your terminal window will display all the requests.
Thanks for taking the time to read my tutorial and if you have any questions please let me know with a comment. If you see any room for improvement feel free to fork the repo and make a pull request!
For more information about the Tokens for Agora applications, please take a look at the Set up Authentication guide and Agora Advanced Guide: How to build a Token(Go).
I also invite you to join the Agora Developer Slack community.