# AccessToken upgrade guide (/en/realtime-media/rtc/build/authenticate-users/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 Video Calling identity management system. This guide shows you how to use Agora token generation libraries to create access tokens.

## 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®:

<Accordions>
  <Accordion title="Token authentication flow">
    ![token authentication flow](https://assets-docs.agora.io/images/video-sdk/token-authentication.svg)
  </Accordion>
</Accordions>

## Prerequisites

Before starting, ensure that you have:

* Implemented the [SDK quickstart](/en/realtime-media/rtc/get-started-sdk) 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

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.

   <Accordions>
     <Accordion title="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\n")

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

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:

   ```go
   go mod init sampleServer
   ```

3. Run the following command to install dependencies.

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

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

   ```go
   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

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

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

* [Token generation code in other languages](/en/realtime-media/rtc/build/authenticate-users/deploy-token-server#token-generation-code)
* [Token generation API reference](/en/realtime-media/rtc/build/authenticate-users/authentication-workflow#api-reference)
