# Use tokens (/en/realtime-media/interactive-live-streaming/build/authenticate-users/use-tokens/electron)

> 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 Interactive Live 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.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

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 [SDK quickstart](../../index.mdx) project you created earlier.

2. In `renderer.js` replace the contents with the following:

**Sample code for basic authentication**

```dart
  const {
      createAgoraRtcEngine,
      VideoMirrorModeType,
      VideoSourceType,
      RenderModeType,
      ChannelProfileType,
      ClientRoleType,
    } = require("agora-electron-sdk");

    let rtcEngine;
    let localVideoContainer;
    let remoteVideoContainer;
    let isJoined = false;

    const EventHandles = {
      // Listen to local user joining channel events
      onJoinChannelSuccess: ({ channelId, localUid }, elapsed) => {
        console.log('Successfully joined the channel：' + channelId);
        isJoined = true;
        // After local users join the channel, set the local video window
        rtcEngine.setupLocalVideo({
          sourceType: VideoSourceType.VideoSourceCameraPrimary,
          view: localVideoContainer,
          mirrorMode: VideoMirrorModeType.VideoMirrorModeDisabled,
          renderMode: RenderModeType.RenderModeFit,
        });
      },

      onLeaveChannel: ({ channelId, localUid }, stats) => {
        console.log('Successfully left the channel:' + channelId);
        isJoined = false;
      },

      // Listen to remote user join event
      onUserJoined: ({ channelId, localUid }, remoteUid, elapsed) => {
        console.log('Remote user ' + remoteUid + ' 已加入');
        // Listen to remote user join event
        rtcEngine.setupRemoteVideoEx(
          {
            sourceType: VideoSourceType.VideoSourceRemote,
            uid: remoteUid,
            view: remoteVideoContainer,
            mirrorMode: VideoMirrorModeType.VideoMirrorModeDisabled,
            renderMode: RenderModeType.RenderModeFit,
          },
          { channelId },
        );
      },

      // Listen for the token expiration event
      onTokenPrivilegeWillExpire: ({ channelId, localUid }, token) => {
        console.log('token ' + token + '即将过期');
        // Obtain a new token from the server
        fetchToken(channelId, localUid, ClientRoleType.ClientRoleBroadcaster)
      },

      // Listen for the token expired event
      onRequestToken: ({ channelId, localUid }) => {
        console.log('token expired');
        token = ''
      }
    };

    // Send a token request to the token server
    function fetchToken(channelName, uid, role) {
      //Token server URL example: http://12.123.1.123:8082/fetch_rtc_token
      const url = '<Your host URL and port>/fetch_rtc_token';
      const body = JSON.stringify({
        uid,
        ChannelName: channelName,
        role
      });
      fetch(url, {
        method: 'POST',
        body,
      })
        .then((res) => res.json())
        .then((res) => {
          console.log('token ' + res.token);
          if (+res.code === 200) {
            if (isJoined) {
              rtcEngine.renewToken(res.token)
            } else {
              rtcEngine.joinChannel(res.token, channelName, uid, { clientRoleType: role })
            }
          }
          return res;
        });
    }

    window.onload = () => {
      const os = require("os");
      const path = require("path");

      // Fill in your app ID
      const APPID = "<Your app ID>";
      // Fill in the channel name
      const channel = "Test";

      localVideoContainer = document.getElementById("join-channel-local-video");
      remoteVideoContainer = document.getElementById("join-channel-remote-video");
      const sdkLogPath = path.resolve(os.homedir(), "./test.log");

      // Create an RtcEngine instance
      rtcEngine = createAgoraRtcEngine();

      // Initialize the RtcEngine instance
      rtcEngine.initialize({
        appId: APPID,
        logConfig: { filePath: sdkLogPath }
      });

      // Register event handler
      rtcEngine.registerEventHandler(EventHandles);

      //Set the channel profile to live broadcast
      rtcEngine.setChannelProfile(ChannelProfileType.ChannelProfileLiveBroadcasting);

      // Set the user role, for host use ClientRoleBroadcaster, for audience use ClientRoleAudience
      rtcEngine.setClientRole(ClientRoleType.ClientRoleBroadcaster);

      // Enable the video module
      rtcEngine.enableVideo();

      // Enable camera preview
      rtcEngine.startPreview();

      // Use the token to join a channel
      // You need to specify the user ID yourself and ensure its uniqueness within the channel
      fetchToken(channel, 123456, ClientRoleType.ClientRoleBroadcaster);
    };
```

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

The sample code implements the following logic:

* Calls `joinChannel` to join a channel using the user ID, the channel name, and a token you obtain from the server. The user ID and channel name you specify must be consistent with the values you used to generate the token.

* The SDK triggers an `onTokenPrivilegeWillExpire` callback 30 seconds before the token expires. After receiving the callback, you obtain a new token from the server and call `renewToken` to pass the newly generated token to the SDK.

* If the token expires, the SDK triggers an `onRequestToken` callback. After receiving the callback, obtain a new token from the server and call `joinChannel` with the new token to rejoin the channel.

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.

### API reference

* [renewToken](https://api-ref.agora.io/en/voice-sdk/electron/4.x/API/class_irtcengine.html#api_irtcengine_renewtoken)
* [onTokenPrivilegeWillExpire](https://api-ref.agora.io/en/voice-sdk/electron/4.x/API/class_irtcengineeventhandler.html#callback_irtcengineeventhandler_ontokenprivilegewillexpire)
* [onRequestToken](https://api-ref.agora.io/en/voice-sdk/electron/4.x/API/class_irtcengineeventhandler.html#callback_irtcengineeventhandler_onrequesttoken)

    
  
      
  
      
  
      
  
      
  
      
  
      
  
      
  
      
  
      
  
