# Use tokens (/en/realtime-media/voice/build/set-up-token-authentication/use-tokens/web)

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

To protect your business, it is best practice to authenticate every client that joins a channel. This guide explains how to fetch an authentication token from your token server, use it to join a channel, and renew the token when it expires.

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

      
  
      
  
      
  
      
    When a user attempts to connect to an Agora channel, your app retrieves a token from the token server in your security infrastructure. Your app then sends this token to Agora SDRTN® for authentication. Agora SDRTN® reads the information stored in the token to validate the request.

    The following figure shows the call flow you implement to create step-up-authentication with Agora Voice Calling:

    **Token authentication flow**

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

    ## Prerequisites [#prerequisites-3]

    Before starting, ensure that you have:

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

    * Deployed a token server using either of the following guides:

      * [Deploy a token server](deploy-token-server.mdx)
      * [Deploy a middleware server](middleware-token-server.md)

    ## Implement basic authentication [#implement-basic-authentication-3]

    This section shows you how to implement basic authentication by acquiring a token and using it to join a channel.

    ### Use a token to join a channel [#use-a-token-to-join-a-channel-3]

    This section shows you how to integrate token authentication in your app.

    1. Open the [Quickstart](../index.mdx) project you created earlier.

    2. In `index.html`, include an HTTP client library such as `axios` for sending token requests to the authentication server.

       ```html
       <html>
         <head>
           <title>Token demo</title>
         </head>
         <script src="https://unpkg.com/axios/dist/axios.min.js"></script>
         <body>
           <h1>Token demo</h1>
           <script src="https://download.agora.io/sdk/release/AgoraRTC_N-4.24.5.js"></script>
           <script src="../agoraLogic.js"></script>
         </body>
       </html>
       ```

    3. Add a `fetchToken` method to retrieve a token from your token server to join a channel.

       ```js
       // Retrieve a token from your token server
       function fetchToken(uid, channelName, tokenRole) {

         return new Promise(function (resolve) {
           axios.post('http://<Your host URL and port>/fetch_rtc_token', {
             uid: uid,
             channelName: channelName,
             role: tokenRole
           }, {
             headers: {
               'Content-Type': 'application/json; charset=UTF-8'
             }
           })
             .then(function (response) {
               const token = response.data.token;
               resolve(token);
             })
             .catch(function (error) {
               console.log(error);
             });
         })
       }
       ```

    4. Use the token to join a channel

       ```js
       // Assign the obtained token to the token parameter in the join method
       let token = await fetchToken(uid, options.channel, 1);
       await client.join(options.appId, options.channel, token, uid);
       ```

    ### Token expiration [#token-expiration-3]

    After you join a channel using a token, the SDK triggers the `token-privilege-will-expire` callback, 30 seconds before the token is set to expire. Upon receiving this callback, retrieve a fresh token from the server and call the `renewToken` method to pass the newly generated token to the SDK.

    ```javascript
    client.on("token-privilege-will-expire", async function () {
      // When you receive the token-privilege-will-expire callback, request a fresh token from the server
      let token = await fetchToken(uid, options.channel, 1);
      // Call renewToken to pass the new token to the SDK
      await client.renewToken(token);
    });
    ```

    When the token expires, the SDK triggers the `token-privilege-did-expire` callback. In this case, retrieve a fresh token from the server and call the `join` method to rejoin the channel with the new token:

    ```javascript
    // The token expired.
    client.on("token-privilege-did-expire", async function () {
    console.log("Fetching a new token")
    // Request a new token from the server
    let token = await fetchToken(uid, options.channel, 1);
    console.log("Rejoining the channel with new token")
    // Call join to rejoin the channel
    await client.join(options.appId, options.channel, token, uid);
    });
    ```

    ### Complete sample code [#complete-sample-code-3]

    For a complete implementation of token authentication, refer to the following code:

    **Sample code for basic authentication**

    ```js
      var rtc = {
          // Set local audio track and video track
          localAudioTrack: null,
          localVideoTrack: null,
        };

        var options = {
          // Fill in app ID
          appId: "<Your app ID>",
          // Fill in a channel name
          channel: "test",
          // Set the user as host or audience
          role: "host"
        };

        // Get a token from your token server

        function fetchToken(uid, channelName, tokenRole) {

          return new Promise(function (resolve) {
            axios.post('http://<Your host URL and port>/fetch_rtc_token', {
              uid: uid,
              channelName: channelName,
              role: tokenRole
            }, {
              headers: {
                'Content-Type': 'application/json; charset=UTF-8'
              }
            })
              .then(function (response) {
                const token = response.data.token;
                resolve(token);
              })
              .catch(function (error) {
                console.log(error);
              });
          })
        }

        async function startBasicCall() {

          const client = AgoraRTC.createClient({ mode: "live", codec: "vp8" });
          client.setClientRole(options.role);
          const uid = 123456;

          // Assign the obtained token to the token parameter of the join method, and join the channel
          let token = await fetchToken(uid, options.channel, 1);

          await client.join(options.appId, options.channel, token, uid);
          rtc.localAudioTrack = await AgoraRTC.createMicrophoneAudioTrack();
          rtc.localVideoTrack = await AgoraRTC.createCameraVideoTrack();
          await client.publish([rtc.localAudioTrack, rtc.localVideoTrack]);
          const localPlayerContainer = document.createElement("div");
          localPlayerContainer.id = uid;
          localPlayerContainer.style.width = "640px";
          localPlayerContainer.style.height = "480px";
          document.body.append(localPlayerContainer);

          rtc.localVideoTrack.play(localPlayerContainer);

          console.log("publish success!");

          client.on("user-published", async (user, mediaType) => {
            await client.subscribe(user, mediaType);
            console.log("subscribe success");

            if (mediaType === "video") {
              const remoteVideoTrack = user.videoTrack;
              const remotePlayerContainer = document.createElement("div");
              remotePlayerContainer.textContent = "Remote user " + user.uid.toString();
              remotePlayerContainer.style.width = "640px";
              remotePlayerContainer.style.height = "480px";
              document.body.append(remotePlayerContainer);
              remoteVideoTrack.play(remotePlayerContainer);

            }

            if (mediaType === "audio") {
              const remoteAudioTrack = user.audioTrack;
              remoteAudioTrack.play();
            }

            client.on("user-unpublished", user => {
              const remotePlayerContainer = document.getElementById(user.uid);
              remotePlayerContainer.remove();
            });

          });

          // When you receive the token-privilege-will-expire callback, request a new token from the server and call renewToken to pass the new token to the SDK
          client.on("token-privilege-will-expire", async function () {
            let token = await fetchToken(uid, options.channel, 1);
            await client.renewToken(token);
          });

          // When you receive the token-privilege-did-expire callback, request a new token from the server and call join to rejoin the channel.
          client.on("token-privilege-did-expire", async function () {
            console.log("Fetching a new token")
            let token = await fetchToken(uid, options.channel, 1);
            console.log("Rejoining the channel with a new token")
            await client.join(options.appId, options.channel, token, uid);
          });

        }

        startBasicCall()
    ```

    Replace `<Your app ID>` with your app ID, which must be consistent with the app ID you specified in the server configuration. Update `<Your Host URL and port>` with the host URL and port of the local Golang server you have deployed. For example `99.9.9.99:8082`.

    Build and run the project on the local device, the app performs the following operations:

    * Obtains a token from your token server.
    * Joins the channel.
    * Automatically renews the token when it is about to expire.

    <CalloutContainer type="info">
      <CalloutDescription>
        The user ID and channel name used to join a channel must be consistent with the values used to generate the token.
      </CalloutDescription>
    </CalloutContainer>

    ## Reference [#reference-3]

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

    
  
      
  
      
  
      
  
      
  
      
  
      
  
      
  
      
  
      
  
      
  
      
  
