salmon-belgium-62133
12/15/2025, 11:03 AMtall-airline-16756
12/15/2025, 11:03 AMtall-airline-16756
12/15/2025, 11:03 AMimport { AccessToken, VideoGrant } from 'livekit-server-sdk';
const at = new AccessToken('API_KEY', 'API_SECRET');
at.identity = 'esp32-device-01';
at.addGrant({ roomJoin: true, room: 'my-room' });
const token = await at.toJwt();
2) Deliver the token to the ESP32 securely
• Send the JWT to the device via HTTPS, MQTT, or another secure channel. Do not embed API keys or secrets in the firmware.
• Use short-lived tokens (e.g., 1 hour) and rotate secrets regularly.
3) Use the token on the ESP32 to connect
• Pass the JWT when creating the LiveKit connection (WebSocket or supported client API).
• Example (C++ style):
room->connect("<wss://your-livekit-server>", "YOUR_JWT_TOKEN");
Security reminders
• Never hardcode API Key/Secret in firmware.
• Issue tokens from a trusted backend only.
• Prefer short TTLs and rotate credentials.
If you’d like, tell me which server language you use (Node/Python/Go) and how you plan to deliver the token (HTTPS, MQTT, etc.) and I’ll give a tailored code example.
Sources: Client SDKs | livekit/livekit_composite | DeepWikisalmon-belgium-62133
12/15/2025, 11:13 AMtall-airline-16756
12/15/2025, 11:14 AMconst at = new AccessToken('API_KEY', 'API_SECRET');
at.identity = 'esp32-device-01';
at.addGrant({ roomJoin: true, room: 'my-room' });
// set TTL in seconds (3600 = 1 hour)
const token = await at.toJwt({ ttl: 3600 });
• Python example (set 1 hour):
token = (
api.AccessToken(api_key="API_KEY", api_secret="API_SECRET")
.with_identity("esp32-device-01")
.with_grants(api.VideoGrants(room_join=True, room="my-room"))
.to_jwt(ttl=3600)
)
3) How to log/check token expiration server-side
• After generating the JWT, decode it (without verifying signature) to read the exp claim and log it:
◦ exp is a UNIX timestamp (seconds); log exp and current time to show TTL.
• Example (Node):
const decoded = JSON.parse(Buffer.from(token.split('.')[1], 'base64').toString());
console.log('token exp (unix):', decoded.exp);
console.log('expires in (s):', decoded.exp - Math.floor(Date.now()/1000));
4) How to confirm token validity on ESP32 (client-side)
• Log connection success/failure when calling `connect()`:
◦ On success, log that the token worked and the connection is established.
◦ On failure, log the error (LiveKit returns authentication/expiry errors if token is invalid or expired).
• Optionally, before using a token on the device, decode the JWT payload server-side and send the exp timestamp to the device so the ESP32 can know when to request a fresh token.
If you want, tell me which server language you're using (Node/Python/Go) and how the ESP32 receives the token (HTTPS/MQTT), and I’ll provide exact code to log exp and handle refresh.salmon-belgium-62133
12/15/2025, 11:15 AMtall-airline-16756
12/15/2025, 11:15 AMroomJoin: true and a room field in the token's VideoGrant.
• The room specifies which room the token is valid for; without it (when roomJoin is true) the server will reject the connection.
If you need a token that can join any room, describe that use case and I can show alternatives or patterns for multi-room access.
Sources: Authentication | LiveKit docs | server-sdk-ruby | livekit/livekit_composite | DeepWikisalmon-belgium-62133
12/15/2025, 11:17 AMtall-airline-16756
12/15/2025, 11:17 AMroomJoin: true and the room name.
• Flow to "create and join" from ESP32:
a. ESP32 requests a token from your backend and indicates the desired room name.
b. Backend generates a JWT (signed with API Key/Secret) with roomJoin: true and room: "your-room", returns the token.
c. ESP32 uses that token to connect; the first join will create the room automatically.
If you want, tell me which server language you use and how the ESP32 will request the token (HTTPS, MQTT, etc.) and I’ll provide a concrete token-generation snippet and a sample ESP32 connect call.
Sources: Connecting to LiveKit | LiveKit docs | Authentication | LiveKit docssalmon-belgium-62133
12/16/2025, 10:54 AMtall-airline-16756
12/16/2025, 10:54 AMws://<host>:7880 or wss://<host>:7880 if TLS). Ensure the ESP32 can reach that host on the network.
• Tokens must still be generated server-side using the same API Key/Secret that the local LiveKit instance is configured with, and the token must include roomJoin: true and the room name.
• If your LiveKit instance uses self-signed TLS, either use ws:// (insecure) on a trusted LAN or configure the ESP32 to trust the server certificate for wss://.
• Typical flow:
a. ESP32 requests a JWT from your backend (backend uses API credentials matched to the local LiveKit).
b. Backend returns JWT with the intended room and TTL.
c. ESP32 connects to ws://<local-ip>:<port> (or wss://...) using the JWT.
• Make sure network routing/firewalls allow the ESP32 to reach the LiveKit host and port.
If you tell me the local server address, whether you’re using TLS, and how the ESP32 will request tokens (HTTPS/MQTT), I’ll provide a concrete connect-snippet and token-generation example for your stack.salmon-belgium-62133
12/16/2025, 10:55 AMtall-airline-16756
12/16/2025, 10:55 AM// Install: npm install express livekit-server-sdk
import express from 'express';
import { AccessToken, VideoGrant } from 'livekit-server-sdk';
const app = express();
app.use(express.json());
const API_KEY = 'key1';
const API_SECRET = 'secret1';
<http://app.post|app.post>('/get-token', (req, res) => {
const { identity = 'esp32-device-01', room = 'test-room', ttl = 3600 } = req.body;
const at = new AccessToken(API_KEY, API_SECRET);
at.identity = identity;
at.addGrant({ roomJoin: true, room });
// toJwt accepts ttl seconds
at.toJwt({ ttl }).then((token) => {
res.json({ token, exp: Math.floor(Date.now()/1000) + ttl });
}).catch(err => res.status(500).json({ error: err.message }));
});
app.listen(3000, () => console.log('token server on <http://localhost:3000'>));
2) How to request the token from ESP32 (pseudo-code)
• ESP32 performs an HTTPS (or HTTP on LAN) POST to http://<backend-host>:3000/get-token with JSON body {"identity":"esp32-01","room":"test-room"}.
• Backend returns { "token": "<JWT>", "exp": ... }.
3) ESP32 connect call (use returned token)
// Pseudo C++ snippet - replace with your ESP32 SDK specifics
String token = "<JWT_FROM_BACKEND>";
room->connect("<ws://localhost:7880>", token.c_str());
Notes and reminders
• Do not hardcode `API_KEY`/`API_SECRET` in firmware — keep them only on your backend.
• The example sets TTL via ttl (seconds). Default used here is 3600s (1 hour); adjust as needed.
• For local testing: use <ws://localhost:7880> if ESP32 and server are on same host or replace with server IP reachable by device. Use wss:// only if certificate is trusted by the ESP32.
• The backend response includes an exp you can log so the device knows when to request a new token.
If you want, tell me which ESP32 SDK/library you’re using for WebSocket/LiveKit connection and I’ll provide a concrete ESP32 code snippet for that SDK.salmon-belgium-62133
12/22/2025, 7:31 AMtall-airline-16756
12/22/2025, 7:32 AMexp (TTL) time has not passed.
• Once the token expires you must generate a new one on your backend and deliver it to the ESP32.
• Best practices:
◦ Use short TTLs (common: 1 hour) so stolen tokens have limited value.
◦ Don’t hardcode API keys/secrets in firmware — generate tokens server-side.
◦ Log or send the token’s exp to the device so it knows when to request a refresh.
◦ For long-lived connections, obtain a fresh token before the current one expires.
If you want, tell me the TTL you’re using and how the ESP32 receives tokens (HTTP/MQTT) and I’ll show code to check exp and refresh automatically.salmon-belgium-62133
12/22/2025, 7:33 AMToken generator server running on port ${PORT});
});tall-airline-16756
12/22/2025, 7:33 AMconst token = await at.toJwt({ ttl: 3600 });
2) Return the token expiration time (exp) to the device so it can refresh before expiry
const expiresAt = Math.floor(Date.now()/1000) + 3600;
res.json({ token, exp: expiresAt });
(Or decode the token server-side to read the exp claim and return that.)
3) Optional: accept a ttl query param for testing
const ttl = parseInt(req.query.ttl) || 3600;
const token = await at.toJwt({ ttl });
res.json({ token, exp: Math.floor(Date.now()/1000) + ttl });
4) Logging for debugging
console.log(`Generated token for ${identity} room=${room} exp=${Math.floor(Date.now()/1000)+ttl}`);
Notes/reminders:
• Do not put `API_KEY`/`API_SECRET` on the ESP32.
• ESP32 can reuse the token until `exp`; regenerate only after expiry (or slightly before).
• If you want, tell me which refresh strategy you prefer (device-initiated before exp, backend push, or refresh-on-failure) and I’ll provide the exact ESP32-side logic to request and swap tokens.