Skip to content

Authentication

了解如何在 LiveKit 會話中驗證使用者身分。

Overview

為了使 LiveKit SDK 成功連接到伺服器,它必須透過請求傳遞存取令牌。

此令牌對參與者的身分、房間名稱、能力和權限進行編碼。存取令牌基於 JWT,並使用您的 API 金鑰進行簽名,以防止偽造。

存取令牌還帶有過期時間,過期後伺服器將拒絕使用該令牌的連線。注意:到期時間僅影響初始連接,而不會影響後續重新連接。

Creating a token

lk token create \
--api-key <KEY> \
--api-secret <SECRET> \
--identity <NAME> \
--room <ROOM_NAME> \
--join \
--valid-for 1h
import { AccessToken, VideoGrant } from 'livekit-server-sdk';

const roomName = 'name-of-room';
const participantName = 'user-name';

const at = new AccessToken('api-key', 'secret-key', {
identity: participantName,
});

const videoGrant: VideoGrant = {
room: roomName,
roomJoin: true,
canPublish: true,
canSubscribe: true,
};

at.addGrant(videoGrant);

const token = await at.toJwt();
console.log('access token', token);
import (
"time"

"github.com/livekit/protocol/auth"
)

func getJoinToken(apiKey, apiSecret, room, identity string) (string, error) {
canPublish := true
canSubscribe := true

at := auth.NewAccessToken(apiKey, apiSecret)
grant := &auth.VideoGrant{
    RoomJoin:     true,
    Room:         room,
    CanPublish:   &canPublish,
    CanSubscribe: &canSubscribe,
}
at.SetVideoGrant(grant).
    SetIdentity(identity).
    SetValidFor(time.Hour)

return at.ToJWT()
}
require 'livekit'

token = LiveKit::AccessToken.new(api_key: 'yourkey', api_secret: 'yoursecret')
token.identity = 'participant-identity'
token.name = 'participant-name'
token.video_grant=(LiveKit::VideoGrant.from_hash(roomJoin: true,
                                                room: 'room-name'))

puts token.to_jwt
import io.livekit.server.*;

public String createToken() {
AccessToken token = new AccessToken("apiKey", "secret");
token.setName("participant-name");
token.setIdentity("participant-identity");
token.setMetadata("metadata");
token.addGrants(new RoomJoin(true), new Room("room-name"));

return token.toJwt();
}
from livekit import api
import os

token = api.AccessToken(os.getenv('LIVEKIT_API_KEY'), os.getenv('LIVEKIT_API_SECRET')) \
    .with_identity("identity") \
    .with_name("name") \
    .with_grants(api.VideoGrants(
        room_join=True,
        room="my-room",
    )).to_jwt()
use livekit_api::access_token;
use std::env;

fn create_token() -> Result<String, AccessTokenError> {
let api_key = env::var("LIVEKIT_API_KEY").expect("LIVEKIT_API_KEY is not set");
let api_secret = env::var("LIVEKIT_API_SECRET").expect("LIVEKIT_API_SECRET is not set");

let token = access_token::AccessToken::with_api_key(&api_key, &api_secret)
    .with_identity("identity")
    .with_name("name")
    .with_grants(access_token::VideoGrants {
        room_join: true,
        room: "my-room".to_string(),
        ..Default::default()
    })
    .to_jwt();
return token
}

對於其他平台,您可以自行實現令牌生成,也可以使用 lk 命令。

令牌簽名相當簡單,請參閱JS 實作作為參考。

LiveKit CLI 可從 https://github.com/livekit/livekit-cli 取得

Token example

以下是連接令牌解碼主體的範例:

{
  "exp": 1621657263,
  "iss": "APIMmxiL8rquKztZEoZJV9Fb",
  "sub": "myidentity",
  "nbf": 1619065263,
  "video": {
    "room": "myroom",
    "roomJoin": true
  },
  "metadata": ""
}
field description
exp Token 的過期時間
nbf Token 生效的開始時間
iss 用於頒發此令牌的 API 金鑰
sub 參與者的唯一身份
metadata 參與者元數據
attributes 參與者屬性(字串的鍵/值對)
video Video grant,包括房間權限(見下文)
sip SIP 授權

Video grant

房間權限在解碼的連線令牌的 video 欄位中指定。它可能包含以下一個或多個屬性:

field type description
roomCreate bool 建立或刪除房間的權限
roomList bool 允許列出可用房間
roomJoin bool 加入房間的權限
roomAdmin bool 管理房間的權限
roomRecord bool 使用 Egress 服務的權限
ingressAdmin bool 使用 Ingress 服務的權限
room string 房間名稱,如果設定了加入或使用 Egress 服務的權限 admin,則為必填項
canPublish bool 允許參與者發布軌道
canPublishData bool 允許參與者向房間發布數據
canPublishSources string[] 需要 canPublish 被設成 true. 設定後,只有列出的來源可以發布。(camera, microphone, screen_share, screen_share_audio)
canSubscribe bool 允許參與者訂閱軌道
canUpdateOwnMetadata bool 允許參與者更新自己的元數據
hidden bool 向房間中的其他人隱藏參與者
kind string 參與者的類型(standard, ingress, egress, sip, or agent)。此欄位通常由 LiveKit 內部設定。

Example: subscribe-only token

要建立參與者只能訂閱而不能發佈到房間的令牌,您可以使用以下授權:

{
  ...
  "video": {
    "room": "myroom",
    "roomJoin": true,
    "canSubscribe": true,
    "canPublish": false,
    "canPublishData": false
  }
}

Example: camera-only

允許參與者發布攝像頭,但禁止其他來源:

{
  ...
  "video": {
    "room": "myroom",
    "roomJoin": true,
    "canSubscribe": true,
    "canPublish": true,
    "canPublishSources": ["camera"]
  }
}

SIP grant

為了與 SIP 服務交互,必須在 JWT 的 sip 欄位中授予權限。它可能包含以下屬性:

field type description
admin bool 管理 SIP 中繼和調度規則的權限。
call bool 透過 CreateSIPParticipant 進行 SIP 通話的權限。

Creating a token with SIP grants

import { AccessToken, SIPGrant, VideoGrant } from 'livekit-server-sdk';

const roomName = 'name-of-room';
const participantName = 'user-name';

const at = new AccessToken('api-key', 'secret-key', {
  identity: participantName,
});

const sipGrant: SIPGrant = { 
  admin: true,
  call: true,
};  

const videoGrant: VideoGrant = { 
  room: roomName,
  roomJoin: true,
};  

at.addGrant(sipGrant);
at.addGrant(videoGrant);

const token = await at.toJwt();
console.log('access token', token);
import (
  "time"

  "github.com/livekit/protocol/auth"
)

func getJoinToken(apiKey, apiSecret, room, identity string) (string, error) {

  at := auth.NewAccessToken(apiKey, apiSecret)

  videoGrant := &auth.VideoGrant{
    RoomJoin:     true,
    Room:         room,
  }

  sipGrant := &auth.SIPGrant{
    Admin:     true,
    Call:      true,
  }

  at.SetSIPGrant(sipGrant).
    SetVideoGrant(videoGrant).
    SetIdentity(identity).
    SetValidFor(time.Hour)

  return at.ToJWT()
}
require 'livekit'

token = LiveKit::AccessToken.new(api_key: 'yourkey', api_secret: 'yoursecret')
token.identity = 'participant-identity'
token.name = 'participant-name'

token.video_grant=(LiveKit::VideoGrant.from_hash(roomJoin: true,
                                                room: 'room-name'))
token.sip_grant=(LiveKit::SIPGrant.from_hash(admin: true, call: true))

puts token.to_jwt
import io.livekit.server.*;

public String createToken() {
  AccessToken token = new AccessToken("apiKey", "secret");

  // Fill in token information.
  token.setName("participant-name");
  token.setIdentity("participant-identity");
  token.setMetadata("metadata");

  // Add room and SIP privileges.
  token.addGrants(new RoomJoin(true), new RoomName("room-name"));
  token.addSIPGrants(new SIPAdmin(true), new SIPCall(true));

  return token.toJwt();
}
from livekit import api
import os

token = api.AccessToken(os.getenv('LIVEKIT_API_KEY'),
                        os.getenv('LIVEKIT_API_SECRET')) \
    .with_identity("identity") \
    .with_name("name") \
    .with_grants(api.VideoGrants(
        room_join=True,
        room="my-room")) \
    .with_sip_grants(api.SIPGrants(
        admin=True,
        call=True)).to_jwt()
use livekit_api::access_token;
use std::env;

fn create_token() -> Result<String, access_token::AccessTokenError> {
    let api_key = env::var("LIVEKIT_API_KEY").expect("LIVEKIT_API_KEY is not set");
    let api_secret = env::var("LIVEKIT_API_SECRET").expect("LIVEKIT_API_SECRET is not set");

    let token = access_token::AccessToken::with_api_key(&api_key, &api_secret)
        .with_identity("rust-bot")
        .with_name("Rust Bot")
        .with_grants(access_token::VideoGrants {
            room_join: true,
            room: "my-room".to_string(),
            ..Default::default()
        })  
        .with_sip_grants(access_token::SIPGrants {
            admin: true,
            call: true
        })  
        .to_jwt();
    return token
}

Room configuration

您可以為使用者建立包含房間配置選項的存取權杖(token)。當為使用者建立房間時,將使用儲存在令牌中的配置來建立房間。例如,當使用者加入房間時,您可以使用它來 explicitly dispatch an agent

有關 RoomConfiguration 欄位的完整列表,請參閱 RoomConfiguration

Creating a token with room configuration

有關顯式代理程式排程的完整範例,請參閱 GitHub 中的範例

import { AccessToken, SIPGrant, VideoGrant } from 'livekit-server-sdk';
import { RoomAgentDispatch, RoomConfiguration } from '@livekit/protocol';

const roomName = 'name-of-room';
const participantName = 'user-name';
const agentName = 'my-agent';

const at = new AccessToken('api-key', 'secret-key', {
  identity: participantName,
});

const videoGrant: VideoGrant = { 
  room: roomName,
  roomJoin: true,
};  

at.addGrant(videoGrant);
at.roomConfig = new RoomConfiguration (
  agents: [
    new RoomAgentDispatch({
      agentName: "test-agent",
      metadata: "test-metadata"
    })
  ]
);

const token = await at.toJwt();
console.log('access token', token);
import (
  "time"

  "github.com/livekit/protocol/auth"
  "github.com/livekit/protocol/livekit"
)

func getJoinToken(apiKey, apiSecret, room, identity string) (string, error) {

  at := auth.NewAccessToken(apiKey, apiSecret)

  videoGrant := &auth.VideoGrant{
    RoomJoin:     true,
    Room:         room,
  }

  roomConfig := &livekit.RoomConfiguration{
    Agents: []*livekit.RoomAgentDispatch{{
      AgentName: "test-agent",
      Metadata:  "test-metadata",
    }}, 
  }

  at.SetVideoGrant(videoGrant).
    SetRoomConfig(roomConfig).
    SetIdentity(identity).
    SetValidFor(time.Hour)

  return at.ToJWT()
}
require 'livekit'

token = LiveKit::AccessToken.new(api_key: 'yourkey', api_secret: 'yoursecret')
token.identity = 'participant-identity'
token.name = 'participant-name'

token.video_grant=(LiveKit::VideoGrant.new(roomJoin: true,
                                          room: 'room-name'))
token.room_config=(LiveKit::Proto::RoomConfiguration.new(
    max_participants: 10
    agents: [LiveKit::Proto::RoomAgentDispatch.new(
      agent_name: "test-agent",
      metadata: "test-metadata",
    )]
  )
)

puts token.to_jwt

有關顯式代理程式排程的完整範例,請參閱 GitHub 中的範例

from livekit import api
import os

token = api.AccessToken(os.getenv('LIVEKIT_API_KEY'),
                        os.getenv('LIVEKIT_API_SECRET')) \
    .with_identity("identity") \
    .with_name("name") \
    .with_grants(api.VideoGrants(
        room_join=True,
        room="my-room")) \
        .with_room_config(
            api.RoomConfiguration(
                agents=[
                    api.RoomAgentDispatch(
                        agent_name="test-agent", metadata="test-metadata"
                    )
                ],
            ),
        ).to_jwt()
use livekit_api::access_token;
use std::env;

fn create_token() -> Result<String, access_token::AccessTokenError> {
    let api_key = env::var("LIVEKIT_API_KEY").expect("LIVEKIT_API_KEY is not set");
    let api_secret = env::var("LIVEKIT_API_SECRET").expect("LIVEKIT_API_SECRET is not set");

    let token = access_token::AccessToken::with_api_key(&api_key, &api_secret)
        .with_identity("rust-bot")
        .with_name("Rust Bot")
        .with_grants(access_token::VideoGrants {
            room_join: true,
            room: "my-room".to_string(),
            ..Default::default()
        })
        .with_room_config(livekit::RoomConfiguration {
            agents: [livekit::AgentDispatch{
              name: "my-agent"
            }]  
        })  
        .to_jwt();
    return token
}

Token refresh

LiveKit 伺服器主動向已連線的用戶端發出刷新的令牌,確保它們在斷開連線時可以重新連線。這些刷新的存取令牌的有效期為 10 分鐘。

此外,當參與者的姓名、權限或元資料變更時,token 也會刷新。

Updating permissions

參與者的權限可以隨時更新,即使他們已經連線。這在參與者的角色可能在會話期間發生變化的應用程式中很有用,例如在參與式直播中。

可以先發出一個帶有 canPublish:false 的令牌,然後在會話期間將其更新為 canPublish:true。可以使用 UpdateParticipant 伺服器 API 變更權限。