Esta página se muestra en inglés. Una traducción al español está en curso.
ScriptsMay 11, 2026·4 min de lectura

LiveKit Token Server — Sign JWTs for Room Access

Server-side token signing for LiveKit rooms. Python/Node SDKs. Per-user permissions, room scoping, TTL. Required for production.

Listo para agents

Este activo puede ser leído e instalado directamente por agents

TokRepo expone un comando CLI universal, contrato de instalación, metadata JSON, plan según adaptador y contenido raw para que los agents evalúen compatibilidad, riesgo y próximos pasos.

Stage only · 17/100Stage only
Superficie agent
Cualquier agent MCP/CLI
Tipo
Skill
Instalación
Stage only
Confianza
Confianza: New
Entrada
Asset
Comando CLI universal
npx tokrepo install 793c4a17-cd72-40f3-aba5-9cb0f5957f1d
Introducción

LiveKit rooms require signed JWT access tokens — your backend signs a token with API key + secret, granting a specific identity permission to join a specific room with specific capabilities (publish, subscribe, record, data). Never sign in the browser. This is the server-side flow with Python and Node examples. Best for: any production LiveKit deployment, multi-tenant voice apps, per-user permission models. Works with: livekit-server-sdk (Python, Node, Go, Ruby, Java). Setup time: 10 minutes.


Python token endpoint (FastAPI)

from livekit import api
from fastapi import FastAPI, HTTPException, Depends
import os

app = FastAPI()

@app.post("/livekit/token")
async def issue_token(user_id: str, room: str, user = Depends(authenticated_user)):
    if not can_join_room(user, room):
        raise HTTPException(403, "not allowed in this room")

    token = (
        api.AccessToken(os.environ["LIVEKIT_API_KEY"], os.environ["LIVEKIT_API_SECRET"])
        .with_identity(user_id)
        .with_name(user.display_name)
        .with_grants(api.VideoGrants(
            room_join=True,
            room=room,
            can_publish=True,
            can_subscribe=True,
            can_publish_data=True,
        ))
        .with_ttl(timedelta(hours=1))
        .to_jwt()
    )
    return {"token": token, "url": os.environ["LIVEKIT_URL"]}

Node token endpoint (Express)

import { AccessToken } from 'livekit-server-sdk';

app.post('/livekit/token', requireAuth, async (req, res) => {
  const { userId, room } = req.body;
  if (!canJoinRoom(req.user, room)) return res.status(403).send();

  const at = new AccessToken(process.env.LIVEKIT_API_KEY, process.env.LIVEKIT_API_SECRET, {
    identity: userId,
    name: req.user.displayName,
    ttl: '1h',
  });
  at.addGrant({
    roomJoin: true,
    room,
    canPublish: true,
    canSubscribe: true,
    canPublishData: true,
  });

  res.json({ token: await at.toJwt(), url: process.env.LIVEKIT_URL });
});

Grant cheat sheet

Grant Use case
room_join Required for any participant
can_publish Participant can publish audio/video
can_subscribe Participant can hear/see others
can_publish_data Send arbitrary chat / state via DataChannel
room_admin Can mute, remove participants
room_record Can start egress recording
ingress_admin Can manage SIP / RTMP ingress

Production hardening

  • Short TTL — 1 hour max for end-user tokens. Browser refreshes via your endpoint.
  • Per-user identity — never reuse identities. user_id should be your DB primary key.
  • Server-side only — never log secrets, never ship API_SECRET to the browser.
  • Cache the SDK — instantiate once, reuse for many tokens.

FAQ

Q: Can I sign tokens in the browser? A: No — the API_SECRET would be exposed. Always sign in your backend. The browser only ever sees the resulting JWT, which has limited TTL and scoped grants.

Q: How do agents get their own token? A: Agents authenticate the same way — your worker process signs an agent identity token (with agent=True grant) before joining the room. LiveKit Cloud agent dispatchers handle this automatically when you deploy via the LiveKit CLI.

Q: What about webhooks for participant join/leave? A: Configure webhooks at cloud.livekit.io → Webhooks. Events: room_started, participant_joined, participant_left, track_published, egress_started. Verify the X-LiveKit-Signature header server-side.


Quick Use

  1. pip install livekit-api or npm install livekit-server-sdk
  2. Build an authenticated POST /livekit/token endpoint in your backend
  3. Frontend POSTs (user_id, room), gets back {token, url}, joins with the SDK

Intro

LiveKit rooms require signed JWT access tokens — your backend signs a token with API key + secret, granting a specific identity permission to join a specific room with specific capabilities (publish, subscribe, record, data). Never sign in the browser. This is the server-side flow with Python and Node examples. Best for: any production LiveKit deployment, multi-tenant voice apps, per-user permission models. Works with: livekit-server-sdk (Python, Node, Go, Ruby, Java). Setup time: 10 minutes.


Python token endpoint (FastAPI)

from livekit import api
from fastapi import FastAPI, HTTPException, Depends
import os

app = FastAPI()

@app.post("/livekit/token")
async def issue_token(user_id: str, room: str, user = Depends(authenticated_user)):
    if not can_join_room(user, room):
        raise HTTPException(403, "not allowed in this room")

    token = (
        api.AccessToken(os.environ["LIVEKIT_API_KEY"], os.environ["LIVEKIT_API_SECRET"])
        .with_identity(user_id)
        .with_name(user.display_name)
        .with_grants(api.VideoGrants(
            room_join=True,
            room=room,
            can_publish=True,
            can_subscribe=True,
            can_publish_data=True,
        ))
        .with_ttl(timedelta(hours=1))
        .to_jwt()
    )
    return {"token": token, "url": os.environ["LIVEKIT_URL"]}

Node token endpoint (Express)

import { AccessToken } from 'livekit-server-sdk';

app.post('/livekit/token', requireAuth, async (req, res) => {
  const { userId, room } = req.body;
  if (!canJoinRoom(req.user, room)) return res.status(403).send();

  const at = new AccessToken(process.env.LIVEKIT_API_KEY, process.env.LIVEKIT_API_SECRET, {
    identity: userId,
    name: req.user.displayName,
    ttl: '1h',
  });
  at.addGrant({
    roomJoin: true,
    room,
    canPublish: true,
    canSubscribe: true,
    canPublishData: true,
  });

  res.json({ token: await at.toJwt(), url: process.env.LIVEKIT_URL });
});

Grant cheat sheet

Grant Use case
room_join Required for any participant
can_publish Participant can publish audio/video
can_subscribe Participant can hear/see others
can_publish_data Send arbitrary chat / state via DataChannel
room_admin Can mute, remove participants
room_record Can start egress recording
ingress_admin Can manage SIP / RTMP ingress

Production hardening

  • Short TTL — 1 hour max for end-user tokens. Browser refreshes via your endpoint.
  • Per-user identity — never reuse identities. user_id should be your DB primary key.
  • Server-side only — never log secrets, never ship API_SECRET to the browser.
  • Cache the SDK — instantiate once, reuse for many tokens.

FAQ

Q: Can I sign tokens in the browser? A: No — the API_SECRET would be exposed. Always sign in your backend. The browser only ever sees the resulting JWT, which has limited TTL and scoped grants.

Q: How do agents get their own token? A: Agents authenticate the same way — your worker process signs an agent identity token (with agent=True grant) before joining the room. LiveKit Cloud agent dispatchers handle this automatically when you deploy via the LiveKit CLI.

Q: What about webhooks for participant join/leave? A: Configure webhooks at cloud.livekit.io → Webhooks. Events: room_started, participant_joined, participant_left, track_published, egress_started. Verify the X-LiveKit-Signature header server-side.


Source & Thanks

Built by LiveKit. Licensed under Apache-2.0.

livekit/python-sdks, livekit/server-sdk-js

🙏

Fuente y agradecimientos

Built by LiveKit. Licensed under Apache-2.0.

livekit/python-sdks, livekit/server-sdk-js

Discusión

Inicia sesión para unirte a la discusión.
Aún no hay comentarios. Sé el primero en compartir tus ideas.

Activos relacionados