whats the issue? ivekit-1 | 2025-09-24T18:56:39.34...
# ask-ai
c
whats the issue? ivekit-1 | 2025-09-24T185639.342Z WARN livekit service/auth.go:95 error handling request {"status": 401, "method": "GET", "path": "/rtc/validate", "error": "invalid token: eyJhbGciOiJIUzI1NiJ9.eyJuYW1lIjoidXNlciIsImF0dHJpYnV0ZXMiOnsiYXNzaXN0YW50X2lkIjoiYTM2NjdkMzktY2I0NC00OTk0LWJlMTktYmE3NzI4MDBlMzU2IiwiY2FtcGFpZ25faWQiOiIzOCIsInNlc3Npb25faWQiOiJ0ZXN0LXNlc3Npb24tZDg2OWY4NDA2MmU5Iiwic291cmNlIjoid2F0Y2h0b3dlciJ9LCJ2aWRlbyI6eyJyb29tIjoidm9pY2VfYXNzaXN0YW50X3Jvb21fNjYxMiIsInJvb21Kb2luIjp0cnVlLCJjYW5QdWJsaXNoIjp0cnVlLCJjYW5QdWJsaXNoRGF0YSI6dHJ1ZSwiY2FuU3Vic2NyaWJlIjp0cnVlfSwicm9vbUNvbmZpZyI6eyJuYW1lIjoiIiwiZW1wdHlUaW1lb3V0IjowLCJkZXBhcnR1cmVUaW1lb3V0IjowLCJtYXhQYXJ0aWNpcGFudHMiOjAsIm1pblBsYXlvdXREZWxheSI6MCwibWF4UGxheW91dERlbGF5IjowLCJzeW5jU3RyZWFtcyI6ZmFsc2UsImFnZW50cyI6W3siYWdlbnROYW1lIjoid2F0Y2h0b3dlciIsIm1ldGFkYXRhIjoiIn1dLCJtZXRhZGF0YSI6IiJ9LCJpc3MiOiJBUElVMjVkc1hqNzd5dzciLCJleHAiOjE3NTg3NDEwOTgsIm5iZiI6MCwic3ViIjoidm9pY2VfYXNzaXN0YW50X3VzZXJfNzA1NCJ9.RPnNJai32OoU7E_POEne-__V4n1vJcW3nh48KKRAw8A, error: proto: (line 1:182): unknown field \"metadata\""} { "name": "user", "attributes": { "assistant_id": "a3667d39-cb44-4994-be19-ba772800e356", "campaign_id": "38", "session_id": "test-session-d869f84062e9", "source": "watchtower" }, "video": { "room": "voice_assistant_room_6612", "roomJoin": true, "canPublish": true, "canPublishData": true, "canSubscribe": true }, "roomConfig": { "name": "", "emptyTimeout": 0, "departureTimeout": 0, "maxParticipants": 0, "minPlayoutDelay": 0, "maxPlayoutDelay": 0, "syncStreams": false, "agents": [ { "agentName": "watchtower", "metadata": "" } ], "metadata": "" }, "iss": "APIU25dsXj77yw7", "exp": 1758741098, "nbf": 0, "sub": "voice_assistant_user_7054" }
t
Thanks for reaching out, ZaidKaraymeh. I'm an AI assistant and I'm here to help. Give me a moment while I research this topic.
It looks like you're encountering the "invalid token" error with status 401, which means the access token provided couldn't be verified or might be malformed. This can happen for a few reasons: • The Authorization header might be missing or not starting with "Bearer ". • The token itself could be invalid or hard to parse. • The API key linked to the token might be invalid or not found in the key provider. • The token verification might fail due to an incorrect secret or expired/invalid claims. The endpoint
/rtc/validate
is designed to check tokens before setting up a WebSocket connection. If the validation doesn't pass, the connection is denied to make sure only clients with valid credentials can join a LiveKit room. To help you move forward, please double-check the token's structure, claims, and the API key it’s associated with. Feel free to reach out if you'd like a hand debugging the token or its setup—I’m here to help! Sources: Web and mobile frontends | LiveKit Docs | pkg/service/rtcservice.go | signalling/signallingbase.go
c
whats hte issue? import { NextRequest, NextResponse } from 'next/server'; import { AccessToken, type AccessTokenOptions, type VideoGrant } from 'livekit-server-sdk'; import { RoomAgentDispatch, RoomConfiguration } from '@livekit/protocol'; import { extractMetadataFromToken } from '@/lib/jwt-utils'; import type { TokenMetadata } from '@/lib/types'; // NOTE: you are expected to define the following environment variables in `.env.local`: const API_KEY = process.env.LIVEKIT_API_KEY; const API_SECRET = process.env.LIVEKIT_API_SECRET; const LIVEKIT_URL = process.env.LIVEKIT_URL; // don't cache the results export const revalidate = 0; export type ConnectionDetails = { serverUrl: string; roomName: string; participantName: string; participantToken: string; }; export async function GET(request: NextRequest) { try { if (LIVEKIT_URL === undefined) { throw new Error('LIVEKIT_URL is not defined'); } if (API_KEY === undefined) { throw new Error('LIVEKIT_API_KEY is not defined'); } if (API_SECRET === undefined) { throw new Error('LIVEKIT_API_SECRET is not defined'); } // Extract token from query parameters const { searchParams } = new URL(request.url); const incomingToken = searchParams.get('token'); // Extract metadata from incoming token if provided let metadata: TokenMetadata | null = null; if (incomingToken) { metadata = extractMetadataFromToken(incomingToken); console.log('Extracted metadata from incoming token:', metadata); } else { console.log('No incoming token provided'); } // Generate participant token const participantName = 'user'; const participantIdentity = `voice_assistant_user_${Math.floor(Math.random() * 10_000)}`; const roomName = `voice_assistant_room_${Math.floor(Math.random() * 10_000)}`; const participantToken = await createParticipantToken( { identity: participantIdentity, name: participantName, metadata: JSON.stringify(metadata) }, roomName, metadata ); console.log('Participant token:', participantToken); // Return connection details const data: ConnectionDetails = { serverUrl: LIVEKIT_URL, roomName, participantToken: participantToken, participantName, }; const headers = new Headers({ 'Cache-Control': 'no-store', }); return NextResponse.json(data, { headers }); } catch (error) { if (error instanceof Error) { console.error(error); return new NextResponse(error.message, { status: 500 }); } } } function createParticipantToken( userInfo: AccessTokenOptions, roomName: string, metadata?: TokenMetadata | null ) { const at = new AccessToken(API_KEY, API_SECRET, { identity: userInfo.identity, name: userInfo.name, ttl: '15m', // Remove the metadata field completely }); const grant: VideoGrant = { room: roomName, roomJoin: true, canPublish: true, canPublishData: true, canSubscribe: true, }; // Only use attributes for your custom data if (metadata) { const stringMetadata: Record<string, string> = {}; Object.entries(metadata).forEach(([key, value]) => { stringMetadata[key] = String(value); }); at.attributes = stringMetadata; } at.addGrant(grant); at.roomConfig = new RoomConfiguration({ agents: [ new RoomAgentDispatch({ agentName: 'watchtower', }), ], }); return at.toJwt(); }
t
It seems like the issue with your code could be related to token generation or configuration. Don’t worry, let’s walk through some common points that might help: • Invalid or missing API keys/secrets: Please double-check that your
LIVEKIT_API_KEY
and
LIVEKIT_API_SECRET
are correctly set in your environment variables. • Missing identity or room: When you generate a token with
roomJoin
permission, make sure both identity and room are specified. • Expiring tokens: Tokens usually have a default expiration time. If you need longer sessions, consider using a custom TTL. • Improper grant configuration: Verify that the
VideoGrant
is properly configured with all the necessary permissions. • Frontend exposure of API secret: For security, generate tokens on the backend and then provide them securely to the frontend. • Invalid room configuration: Ensure that the room configuration is correctly formatted when included in the token. In your code, it would be helpful to check that the
createParticipantToken
function is setting all the required fields properly and that the metadata is formatted as expected. If you’d like, I’m here to help you debug any specific parts of your implementation—just let me know! Sources: auth/accesstoken.go | livekit-api/src/access_token.rs | packages/livekit-server-sdk/src/AccessToken.test.ts | src/test/kotlin/io/livekit/server/AccessTokenTest.kt | Authentication | LiveKit Docs
c
the same was code was working when i did wtih dev command, now doing start
t
I understand how tricky it can be when things work in development but not in production. Often, this happens because the environments are set up differently. In development, placeholder credentials or sandbox setups might be fine, but production needs everything properly configured. Let’s walk through some important points to check together: • Environment Variables: Please make sure
LIVEKIT_API_KEY
,
LIVEKIT_API_SECRET
, and
LIVEKIT_URL
are correctly set in your production environment. • Token Generation: Double-check that tokens are being generated using the LiveKit Server SDK with valid API keys and secrets. • Environment-Specific Configurations: It’s important your application uses the right server URLs and credentials for production. • Token TTL: Keep in mind that development tokens might last longer, while production tokens usually expire faster. Make sure your app can handle token renewal if needed. • Backend Setup: Verify that your backend can reach the LiveKit service and is set up to generate tokens dynamically. If you’d like, I’m here to help you go through these steps or troubleshoot any specific issues you’re facing. Just let me know! Sources: README.md | Generating tokens | LiveKit Docs | agent-console/app/api/token/route.ts | cmd/server/main.go | Development Environment Setup | livekit/livekit_composite | DeepWiki