# AccessToken upgrade guide (/en/realtime-media/voice/build/set-up-token-authentication/integrate-token-generation)

> For AI agents: see the complete documentation index at [llms.txt](/llms.txt).

To secure user access, integrate token authentication into your Voice Calling identity management system. This guide shows you how to use Agora token generation libraries to create access tokens.

## Understand the tech [#understand-the-tech]

A token contains the following information:

* The App ID for your project
* The App certificate for your project
* Channel name
* User ID
* User permissions, such as whether they can send or receive streams
* Token expiration Unix timestamp

When a user attempts to connect to an Agora channel, your app requests a token from your authentication system. Your authentication system uses Agora libraries to generate a token specific to the user and the channel, then sends it to your app. The app then sends this token to Agora SDRTN® with the request to join a channel. Agora SDRTN® validates the token and adds the user to the channel. The following diagram shows the authentication call flow between your app, your authentication system and Agora SDRTN®:

**Token authentication flow**

![token authentication flow](https://assets-docs.agora.io/images/video-sdk/token-authentication.svg)

## Prerequisites [#prerequisites]

Before starting, ensure that you have:

* Implemented the [SDK quickstart](../index.mdx) in your project.

* The following information from [Agora Console](https://console.agora.io/v2):
  * App ID: A unique string generated by Agora that identifies your project.
  * App Certificate: A string generated by Agora Console to enable token authentication. To obtain the App Certificate for your project, enable primary certificate.

## Deploy a token server [#deploy-a-token-server]

This section shows you how to quickly deploy a token server based on `AccessToken2`. If you already have a token server that uses `AccessToken` skip to [Upgrade to `AccessToken2`.](#upgrade-to-accesstoken2).

The following example uses Golang. Before starting, ensure that you have [Golang](https://golang.org/dl/) version 1.14 or above.

Follow these steps to build and run a token generator locally:

1. Create a new `token-server` folder. Create a `server.go` file inside the folder and paste the following Golang sample code into the file. Replace the values for `appID` and `appCertificate` with your App ID and App certificate.

   **Sample code for a token server**

   ```go
     package main

   import (
     rtctokenbuilder "github.com/AgoraIO/Tools/DynamicKey/AgoraDynamicKey/go/src/rtctokenbuilder2"
     "fmt"
     "log"
     "net/http"
     "encoding/json"
     "errors"
     "strconv"
   )

   type rtc_int_token_struct struct{
     Uid_rtc_int uint32 `json:"uid"`
     Channel_name string `json:"ChannelName"`
     Role uint32 `json:"role"`
   }

   var rtc_token string
   var int_uid uint32
   var channel_name string

   var role_num uint32
   var role rtctokenbuilder.Role

   // Use RtcTokenBuilder to generate RTC Token
   func generateRtcToken(int_uid uint32, channelName string, role rtctokenbuilder.Role){
     appID := "<Your App ID>"
     appCertificate := "<Your App Certificate>"
     // Ensure that the expiration time of the token is later than the permission expiration time. Permission expiration time, unit is seconds
     tokenExpireTimeInSeconds := uint32(40)
     // The token-privilege-will-expire callback is triggered 30 seconds before the permission expires.
     // For demonstration purposes, set the expiration time to 40 seconds. You can see the process of the client automatically updating the Token
     privilegeExpireTimeInSeconds := uint32(40)

     result, err := rtctokenbuilder.BuildTokenWithUid(appID, appCertificate, channelName, int_uid, role, tokenExpireTimeInSeconds, privilegeExpireTimeInSeconds)
     if err != nil {
       fmt.Println(err)
     } else {
         fmt.Printf("Token with uid: %s\n", result)
         fmt.Printf("uid is %d\n", int_uid )
         fmt.Printf("ChannelName is %s\n", channelName)
         fmt.Printf("Role is %d\n", role)
     }
     rtc_token = result
   }

   func rtcTokenHandler(w http.ResponseWriter, r *http.Request){
     w.Header().Set("Content-Type", "application/json; charset=UTF-8")
     w.Header().Set("Access-Control-Allow-Origin", "*")
     w.Header().Set("Access-Control-Allow-Methods", "POST, OPTIONS");
     w.Header().Set("Access-Control-Allow-Headers", "*");

     if r.Method == "OPTIONS" {
       w.WriteHeader(http.StatusOK)
       return
     }

     if r.Method != "POST" && r.Method != "OPTIONS" {
       http.Error(w, "Unsupported method. Please check.", http.StatusNotFound)
       return
     }

     var t_int rtc_int_token_struct
     var unmarshalErr *json.UnmarshalTypeError
     int_decoder := json.NewDecoder(r.Body)
     int_err := int_decoder.Decode(&t_int)
     if (int_err == nil) {

           int_uid = t_int.Uid_rtc_int
           channel_name = t_int.Channel_name
           role_num = t_int.Role
           switch role_num {
             case 1:
               role = rtctokenbuilder.RolePublisher
             case 2:
               role = rtctokenbuilder.RoleSubscriber
           }
     }
     if (int_err != nil) {

       if errors.As(int_err, &unmarshalErr){
           errorResponse(w, "Bad request. Wrong type provided for field " + unmarshalErr.Value + unmarshalErr.Field + unmarshalErr.Struct, http.StatusBadRequest)
           } else {
           errorResponse(w, "Bad request.", http.StatusBadRequest)
         }
       return
     }

     generateRtcToken(int_uid, channel_name, role)
     errorResponse(w, rtc_token, http.StatusOK)
     log.Println(w, r)
   }

   func errorResponse(w http.ResponseWriter, message string, httpStatusCode int){
     w.Header().Set("Content-Type", "application/json")
     w.Header().Set("Access-Control-Allow-Origin", "*")
     w.WriteHeader(httpStatusCode)
     resp := make(map[string]string)
     resp["token"] = message
     resp["code"] = strconv.Itoa(httpStatusCode)
     jsonResp, _ := json.Marshal(resp)
     w.Write(jsonResp)
   }

   func main(){
     // Use int type uid to generate RTC Token
     http.HandleFunc("/fetch_rtc_token", rtcTokenHandler)
     fmt.Printf("Starting server at port 8082
   ")

     if err := http.ListenAndServe(":8082", nil); err != nil {
       log.Fatal(err)
     }
   }
   ```

2. Open the terminal, go to the `token-server` folder path, and run the following command line to create a `go.mod` file for your token generator. This file defines the import path and dependencies:

   ```bash
   go mod init sampleServer
   ```

3. Run the following command to install dependencies.

   ```bash
   go get github.com/AgoraIO/Tools/DynamicKey/AgoraDynamicKey/go/src/rtctokenbuilder2
   ```

4. Run the following command to start the token generator:

   ```bash
   go run server.go
   ```

After the token generator is deployed successfully, your terminal returns the token generated based on the App ID and App certificate you filled in.

## Reference [#reference]

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

### Upgrade to AccessToken2 [#upgrade-to-accesstoken2]

If your current token server implementation uses `AccessToken`, follow these steps to upgrade your server to `AccessToken2`.

1. Replace the import `rtctokenbuilder` declaration with the following code and delete the declaration that imports `time`:

   ```go
   import (
     // Replace
     // rtctokenbuilder "github.com/AgoraIO/Tools/DynamicKey/AgoraDynamicKey/go/src/RtcTokenBuilder"
     rtctokenbuilder "github.com/AgoraIO/Tools/DynamicKey/AgoraDynamicKey/go/src/rtctokenbuilder2"
     "fmt"
     "log"
     "net/http"
     // delete
     // "time"
     "encoding/json"
     "errors"
     "strconv"
   )
   ```

2. Remove the statement that generates the timestamp and add `tokenExpireTimeInSeconds` and `privilegeExpireTimeInSeconds` related code:

   ```go
   // expireTimeInSeconds := uint32(40)
   // Get the current timestamp
   // currentTimestamp := uint32(time.Now().UTC().Unix())
   // Timestamp when the token expires.
   // expireTimestamp := currentTimestamp + expireTimeInSeconds
   tokenExpireTimeInSeconds := uint32(40)
   privilegeExpireTimeInSeconds := uint32(40)
   ```

3. Update `tokenbuilder` method code:

   ```go
   // Code before updating
   // result, err := rtctokenbuilder.BuildTokenWithUID(appID, appCertificate, channelName, int_uid, role, expireTimestamp)
   // Updated code
   // Change BuildTokenWithUID to BuildTokenWithUid
   // Change expireTimestamp to tokenExpireTimeInSeconds and privilegeExpireTimeInSeconds
   result, err := rtctokenbuilder.BuildTokenWithUid(appID, appCertificate, channelName, int_uid, role, tokenExpireTimeInSeconds, privilegeExpireTimeInSeconds)
   ```

4. Remove unsupported roles

   ```go
   switch role_num {
   // delete
   // case 0:
     // Deprecated. RoleAttendee and RolePublisher have the same permissions
     // role = rtctokenbuilder.RoleAttendee
     case 1:
       role = rtctokenbuilder.RolePublisher
     case 2:
       role = rtctokenbuilder.RoleSubscriber
   // delete
   // case 101:
     // Deprecated. RoleAdmin and RolePublisher have the same permissions
     // role = rtctokenbuilder.RoleAdmin
   }
   ```

### See also [#see-also]

* [Token generation code in other languages](use-tokens.mdx)
* [Token generation API reference](use-tokens.mdx)
