# Use tokens (/en/realtime-media/broadcast-streaming/build/authenticate-users/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

      
  
      
  
      
  
      
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 Broadcast Streaming:

**Token authentication flow**

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

## Prerequisites

Before starting, ensure that you have:

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

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

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

## Implement basic authentication

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

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

1. Open the [Quickstart](../../index) 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.7.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

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

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

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

    
  
      
  
      
  
      
  
      
  
      
  
      
  
      
  
      
  
      
  
      
  
      
  
