# Token generators (/en/realtime-media/cloud-recording/build/set-up-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 Cloud Recording 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®:

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

## Prerequisites [#prerequisites]

Before starting, ensure that you have:

* Implemented the [SDK quickstart](/video-calling/get-started/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 [#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 [#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](./authentication-workflow#token-generation-code)
* [Token generation API reference](./authentication-workflow#api-reference)
