Back to Blog

Build an Agora Token Server Using Java

Build an Agora Token Server Using Java

This blog was written by Sai Sandeep Rayanuthala, an Agora Superstar. The Agora Superstar program empowers developers around the world to share their passion and technical expertise, and create innovative real-time communications apps and projects using Agora’s customizable SDKs.


Security for video chat applications is very important. In the Agora platform, one layer of security comes in the form of token authentication. This guide explains how to build a simple microservice using Java and Jersey to generate an Agora RTC token.

Prerequisites

  1. Apache Tomcat, IntelliJ IDEA IDE, Jersey framework, and Docker.
  2. Basic understanding about how the REST framework works.
  3. Basic understanding of classes in Java.
  4. Agora developer account.

What you’ll do today:

  1. Build a Jersey project.
  2. Create a Hello World API.
  3. Generate Agora token.
  4. Dockerize application and deploy it on a Ubuntu VM.

Project Setup

Archetype: Archetype is a Maven project templating toolkit.

Artifact: An artifact is a file, usually a JAR file, that gets deployed to a Maven repository. A Maven build produces one or more artifacts, such as a compiled JAR file and a source JAR file.

jersey-quickstart-webapp provides a basic project template to work on. It is very useful for beginners and powerful enough.

Open your IntelliJ IDE and click start new project. We are gonna build it using Maven. Click Create from Archetype and add an Archetype with the following configuration.

Group Id: org.glassfish.jersey.archetypes
Artifact Id: jersey-quickstart-webapp
Version: 2.31

The final configuration of the project looks like this:

Once your project is built, we will add the Tomcat server. If you don’t have one installed you can get Tomcat from this link. After completing the installation of Tomcat you can click Add Configuration, which is next to the build icon.

From templates choose Local Tomcat Server. The final configuration looks like this:

Once you’re done apply the configuration and close the configuration window. You are done setting up your Jersey project and configured Tomcat server.

Hello World API

In this section, you create a Hello World API with JSON and XML input and output.

Navigate to pom.xml (which holds all the Maven dependencies), uncomment the JSON dependency, and add the JAVAX dependency. Your dependencies should look like this:

<dependencies>
<dependency>
<groupId>org.glassfish.jersey.containers</groupId>
<artifactId>jersey-container-servlet-core</artifactId>
</dependency>
<dependency>
<groupId>org.glassfish.jersey.inject</groupId>
<artifactId>jersey-hk2</artifactId>
</dependency>
<dependency>
<groupId>org.glassfish.jersey.media</groupId>
<artifactId>jersey-media-json-binding</artifactId>
</dependency>
<dependency>
<groupId>javax.ws.rs</groupId>
<artifactId>javax.ws.rs-api</artifactId>
<version>2.1.1</version>
</dependency>
<dependency>
<groupId>commons-codec</groupId>
<artifactId>commons-codec</artifactId>
<version>1.6</version>
</dependency>
<dependency>
<groupId>com.googlecode.json-simple</groupId>
<artifactId>json-simple</artifactId>
<version>1.1.1</version>
</dependency>
</dependencies>
view raw pom.xml hosted with ❤ by GitHub

Edit src/main/webapp/index.JSP and add the following code to the file:

<html>
<body>
<h2>Agora Token Server</h2>
<p><a href="webapi/myresource">Agora resource</a>
<p>Visit <a href="https://agora.io/">Agora.io website</a>
for more information on Agora!
</body>
</html>
view raw index.JSP hosted with ❤ by GitHub

Now build the project. After a successful build, IntelliJ opens the browser for you. By default, the index.JSP file is displayed in the browser. The browser should show something like this:


Click jersey resource, which redirects you to a new page:

Notice the URL. By default, ServerletMapping maps everything to /webapi/*. You change that to /*.

<?xml version="1.0" encoding="UTF-8"?>
<web-app version="2.5" xmlns="http://java.sun.com/xml/ns/javaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd">
<servlet>
<servlet-name>Agora Token Server</servlet-name>
<servlet-class>org.glassfish.jersey.servlet.ServletContainer</servlet-class>
<init-param>
<param-name>jersey.config.server.provider.packages</param-name>
<param-value>com.sandeep.agoratoken</param-value> <!-- Remember to replace this -->
</init-param>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>Agora Token Server</servlet-name>
<url-pattern>/webapi/*</url-pattern>
</servlet-mapping>
</web-app>

Restart the server. webapi is removed.

How did “Got it!” appear on the website? Head to the MyResource Java class. It looks something like this:

Here we added a Path annotation (@ PATH). which is used to define a URI matching pattern for incoming HTTP requests for the MyResource class.

We got “myresource” in the URL due to this Path annotation ( i.e., @ PATH(“myresource”) ). We defined @ GET (line 12) for the getIt() method, which specifies that this will use the GET HTTP method. @ Produces annotation (line 13) defines the return response format.

Now you add Agora to the project.

Go on to https://bit.ly/AgoraJAVAGithub, clone the whole repository, and copy and paste the Media and RTM folders. The file structure should look like this:

Note: Go to every file and correct the package name to avoid errors. In my case, it should be com.sandeep.agoratoken instead of io.agora. Usually, IntelliJ does this for you.

Once you are done create 3 new java classes by right-clicking the java folder named Agora, AgoraRepository, and AgoraRTMRepository, and delete the MyResource file.

Paste the following code in your AgoraRepository:

package com.sandeep.agoratoken; //make sure you change this
public class AgoraRepository {
static String appId = "APP_ID";
static String appCertificate ="APP_CERIFICATE";
private String channelName;
private int uid = 0; // By default 0
private int expirationTimeInSeconds = 3600; // By default 3600
private int role = 2; // By default subscriber
}

Paste the following code in your AgoraRTMRepository:

package com.sandeep.agoratoken;
public class AgoraRTMRepository {
private static String appId = "APP_ID";
private static String appCertificate = "APP_CERT";
private String userId;
private int expireTimestamp = 0;
}

Now you need getters and setters.

Go to AgoraRepository class and enter the command for your operating system:

* Ctrl + N for Linux and Windows users

Alternative for above commands

Your file should look like this:

package com.sandeep.agoratoken;
public class AgoraRepository {
static String appId = "APP_ID"; //replace app id
static String appCertificate = "APP_CERT"; //replace app cert
private String channelName;
private int uid = 0;
private int expirationTimeInSeconds = 3600;
private int role = 2; // By default subscriber
public static String getAppId() {
return appId;
}
public static void setAppId(String appId) {
AgoraRepository.appId = appId;
}
public static String getAppCertificate() {
return appCertificate;
}
public static void setAppCertificate(String appCertificate) {
AgoraRepository.appCertificate = appCertificate;
}
public String getChannelName() {
return channelName;
}
public void setChannelName(String channelName) {
this.channelName = channelName;
}
public int getUid() {
return uid;
}
public void setUid(int uid) {
this.uid = uid;
}
public int getExpirationTimeInSeconds() {
return expirationTimeInSeconds;
}
public void setExpirationTimeInSeconds(int expirationTimeInSeconds) {
this.expirationTimeInSeconds = expirationTimeInSeconds;
}
public int getRole() {
return role;
}
public void setRole(int role) {
this.role = role;
}
}

Repeat this step in AgoraRTMRepository. Your file should now look like this:

package com.sandeep.agoratoken;
public class AgoraRTMRepository {
private static String appId = "APP_ID";
private static String appCertificate = "APP_CERT";
private String userId = "USER_ID";
private int expireTimestamp = 0;
public static String getAppId() {
return appId;
}
public static String getAppCertificate() {
return appCertificate;
}
public static void setAppCertificate(String appCertificate) {
AgoraRTMRepository.appCertificate = appCertificate;
}
public String getUserId() {
return userId;
}
public int getExpireTimestamp() {
return expireTimestamp;
}
public static void setAppId(String appId) {
AgoraRTMRepository.appId = appId;
}
}

You can see something like this. Click Getter and Setter and select everything. We are almost done with Agora Token Server.

Import stuff and define the Token Server RTC POST Request:

package com.sandeep.agoratoken;
import com.sandeep.agoratoken.media.RtcTokenBuilder;
import javax.ws.rs.POST;
import javax.ws.rs.Path;
import javax.ws.rs.Produces;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.Response;
import org.json.simple.JSONObject;
@Path("api")
public class Agora{
@POST
@Path("rtc")
@Produces(MediaType.APPLICATION_JSON)
public Object getRTCToken(AgoraRepository resource) {
}
}
view raw Agora.java hosted with ❤ by GitHub

Initialize all parameters:

package com.sandeep.agoratoken;
import com.sandeep.agoratoken.media.RtcTokenBuilder;
import javax.ws.rs.POST;
import javax.ws.rs.Path;
import javax.ws.rs.Produces;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.Response;
import org.json.simple.JSONObject;
@Path("api")
public class Agora{
@POST
@Path("rtc")
@Produces(MediaType.APPLICATION_JSON)
public Object getRTCToken(AgoraRepository resource) {
RtcTokenBuilder token = new RtcTokenBuilder();
String channelName = resource.getChannelName();
int expireTime = resource.getExpirationTimeInSeconds();
RtcTokenBuilder.Role role = RtcTokenBuilder.Role.Role_Subscriber;
int uid = resource.getUid();
}
}
view raw Agora.java hosted with ❤ by GitHub

Do some checks before creating the tokens to make sure everything is correct:

package com.sandeep.agoratoken;
import com.sandeep.agoratoken.media.RtcTokenBuilder;
import javax.ws.rs.POST;
import javax.ws.rs.Path;
import javax.ws.rs.Produces;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.Response;
import org.json.simple.JSONObject;
@Path("api")
public class Agora{
@POST
@Path("rtc")
@Produces(MediaType.APPLICATION_JSON)
public Object getRTCToken(AgoraRepository resource) {
RtcTokenBuilder token = new RtcTokenBuilder();
String channelName = resource.getChannelName();
int expireTime = resource.getExpirationTimeInSeconds();
RtcTokenBuilder.Role role = RtcTokenBuilder.Role.Role_Subscriber;
int uid = resource.getUid();
// check for null channelName
if (channelName==null){
JSONObject error=new JSONObject();
error.put("error","Channel ID cannot be blank");
return Response.status(Response.Status.BAD_REQUEST).entity(error).build();
}
if(expireTime==0){
expireTime = 3600;
}
if(resource.getRole()==1){
role = RtcTokenBuilder.Role.Role_Publisher;
}else if(resource.getRole()==0){
role = RtcTokenBuilder.Role.Role_Attendee;
}
}
}
view raw Agora.java hosted with ❤ by GitHub

Create a timestamp and complete the generation of token:

package com.sandeep.agoratoken;
import com.sandeep.agoratoken.media.RtcTokenBuilder;
import javax.ws.rs.POST;
import javax.ws.rs.Path;
import javax.ws.rs.Produces;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.Response;
import org.json.simple.JSONObject;
@Path("api")
public class Agora{
@POST
@Path("rtc")
@Produces(MediaType.APPLICATION_JSON)
public Object getRTCToken(AgoraRepository resource) {
RtcTokenBuilder token = new RtcTokenBuilder();
String channelName = resource.getChannelName();
int expireTime = resource.getExpirationTimeInSeconds();
RtcTokenBuilder.Role role = RtcTokenBuilder.Role.Role_Subscriber;
int uid = resource.getUid();
// check for null channelName
if (channelName==null){
JSONObject error=new JSONObject();
error.put("error","Channel ID cannot be blank");
return Response.status(Response.Status.BAD_REQUEST).entity(error).build();
}
if(expireTime==0){
expireTime = 3600;
}
if(resource.getRole()==1){
role = RtcTokenBuilder.Role.Role_Publisher;
}else if(resource.getRole()==0){
role = RtcTokenBuilder.Role.Role_Attendee;
}
int timestamp = (int)(System.currentTimeMillis() / 1000 + expireTime);
String result = token.buildTokenWithUid(resource.appId, resource.appCertificate,
channelName, uid, role, timestamp);
System.out.print(result);
JSONObject jsondict = new JSONObject();
jsondict.put("message",result);
return jsondict;
}
}
view raw Agora.java hosted with ❤ by GitHub

Hurray! You’re done building the Agora Java RTC token server. Now it’s time to get started with Agora RTM token server.

Add the following code to your Agora class:

@POST
@Path("rtm")
@Produces(MediaType.APPLICATION_JSON)
public Object getRTMToken(AgoraRTMRepository resource) throws Exception {
String userId = resource.getUserId();
if (userId==null){
JSONObject error=new JSONObject();
error.put("error","User ID cannot be blank");
return Response.status(Response.Status.BAD_REQUEST).entity(error).build();
}
RtmTokenBuilder token = new RtmTokenBuilder();
String result = token.buildToken(resource.getAppId(), resource.getAppCertificate(), userId, Role.Rtm_User, resource.getExpireTimestamp());
System.out.println(result);
JSONObject jsondict = new JSONObject();
jsondict.put("message",result);
return jsondict;
}
view raw Agora.java hosted with ❤ by GitHub

Your final code should look like this:

package com.sandeep.agoratoken;
import com.sandeep.agoratoken.media.RtcTokenBuilder;
import com.sandeep.agoratoken.rtm.RtmTokenBuilder;
import com.sandeep.agoratoken.rtm.RtmTokenBuilder.Role;
import javax.ws.rs.POST;
import javax.ws.rs.Path;
import javax.ws.rs.Produces;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.Response;
import org.json.simple.JSONObject;
@Path("api")
public class Agora{
@POST
@Path("rtc")
@Produces(MediaType.APPLICATION_JSON)
public Object getRTCToken(AgoraRepository resource) {
RtcTokenBuilder token = new RtcTokenBuilder();
String channelName = resource.getChannelName();
int expireTime = resource.getExpirationTimeInSeconds();
RtcTokenBuilder.Role role = RtcTokenBuilder.Role.Role_Subscriber;
int uid = resource.getUid();
// check for null channelName
if (channelName==null){
JSONObject error=new JSONObject();
error.put("error","Channel ID cannot be blank");
return Response.status(Response.Status.BAD_REQUEST).entity(error).build();
}
if(expireTime==0){
expireTime = 3600;
}
if(resource.getRole()==1){
role = RtcTokenBuilder.Role.Role_Publisher;
}else if(resource.getRole()==0){
role = RtcTokenBuilder.Role.Role_Attendee;
}
int timestamp = (int)(System.currentTimeMillis() / 1000 + expireTime);
String result = token.buildTokenWithUid(resource.appId, resource.appCertificate,
channelName, uid, role, timestamp);
System.out.print(result);
JSONObject jsondict = new JSONObject();
jsondict.put("message",result);
return jsondict;
}
@POST
@Path("rtm")
@Produces(MediaType.APPLICATION_JSON)
public Object getRTMToken(AgoraRTMRepository resource) throws Exception {
String userId = resource.getUserId();
if (userId==null){
JSONObject error=new JSONObject();
error.put("error","User ID cannot be blank");
return Response.status(Response.Status.BAD_REQUEST).entity(error).build();
}
RtmTokenBuilder token = new RtmTokenBuilder();
String result = token.buildToken(resource.getAppId(), resource.getAppCertificate(), userId, Role.Rtm_User, resource.getExpireTimestamp());
System.out.println(result);
JSONObject jsondict = new JSONObject();
jsondict.put("message",result);
return jsondict;
}
}
view raw Agora.java hosted with ❤ by GitHub

Are we done? No, there’s still deployment.

Deployment

First, you need to create a WAR file. Open Maven from the right toggle bar, and click the Maven Icon to execute a command:

Now run mvn clean package

A WAR File is generated in a minute or two. You can see the location of the WAR file.

Create a Dockerfile in your repository, and push your code to GitHub.

FROM tomcat:9.0.37
MAINTAINER SaiSandeep
COPY target/agoratoken.war /usr/local/tomcat/webapps/ROOT.war
EXPOSE 8080
CMD ["catalina.sh", "run"]
view raw Dockerfile hosted with ❤ by GitHub

Create a Ubuntu VM.

Run the following commands to install Docker on Linux:

sudo apt-get update

sudo apt-get install \
    apt-transport-https \
    ca-certificates \
    curl \
    gnupg-agent \
    software-properties-common

curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo apt-key add -

sudo add-apt-repository \
   "deb [arch=amd64] https://download.docker.com/linux/ubuntu \
   $(lsb_release -cs) \
   stable"

sudo apt-get update

sudo apt-get install docker-ce docker-ce-cli containerd.io

Mac and Windows users can get the executable file from this link.

Run this command to check if Docker is installed -> docker -v

Clone your repository into your VM. And run the following command:

nano src/main/java/com/sandeep/agoratoken/MyResourceRepository.java

Fill your APP_ID and APP_CERT. You can get APP_ID and APP_CERT from your Agora Console.

To build the Docker image, run the following command:

docker build -t agoratoken ./

OK, run it!

docker run -p 80:8080 agoratoken

Check the API.

Other Resources

For more information about the tokens for Agora applications, please take a look at the Setup Authentication guide and Agora Advanced Guide: How to build a Token(Go).

I also invite you to join the Agora Developer Slack community.

Github repo: https://github.com/raysandeep/AgoraToken

RTE Telehealth 2023
Join us for RTE Telehealth - a virtual webinar where we’ll explore how AI and AR/VR technologies are shaping the future of healthcare delivery.

Learn more about Agora's video and voice solutions

Ready to chat through your real-time video and voice needs? We're here to help! Current Twilio customers get up to 2 months FREE.

Complete the form, and one of our experts will be in touch.

Try Agora for Free

Sign up and start building! You don’t pay until you scale.
Try for Free