// A minimal "tenant backend": the only place the secret API key lives. Browsers call GET /token and get a // short-lived, channel-scoped agent token; they never see the API key. // // CYBERPLEX_URL=https://cyberplex.replit.app CYBERPLEX_API_KEY=ak_... ALLOW_ORIGIN=https://your-site.example \ // node token-server.mjs // // !! This sample hands a token to ANYONE who can reach it. In a real app, check your own user session // !! first, and derive agentId/channels from the logged-in user instead of the query string. import { createServer } from 'node:http'; import { randomBytes } from 'node:crypto'; const GATEWAY = process.env.CYBERPLEX_URL ?? 'https://cyberplex.replit.app'; const API_KEY = process.env.CYBERPLEX_API_KEY; const ALLOW_ORIGIN = process.env.ALLOW_ORIGIN; // the page's origin, e.g. https://app.example.com const CHANNELS = (process.env.CHANNELS ?? 'room-*').split(','); // what a token may touch: names or prefix* const PORT = Number(process.env.PORT ?? 4000); if (!API_KEY) throw new Error('set CYBERPLEX_API_KEY to your tenant API key'); createServer(async (req, res) => { const url = new URL(req.url ?? '/', 'http://x'); const cors = ALLOW_ORIGIN && req.headers.origin === ALLOW_ORIGIN ? { 'access-control-allow-origin': ALLOW_ORIGIN, vary: 'Origin' } : { vary: 'Origin' }; if (req.method === 'OPTIONS') return void res.writeHead(204, { ...cors, 'access-control-allow-methods': 'GET', 'access-control-allow-headers': 'content-type' }).end(); if (url.pathname !== '/token' || req.method !== 'GET') return void res.writeHead(404, cors).end(); const agentId = (url.searchParams.get('agent') ?? '').replace(/[^A-Za-z0-9_-]/g, '').slice(0, 40) || `web-${randomBytes(4).toString('hex')}`; const r = await fetch(`${GATEWAY}/v1/agent-token`, { method: 'POST', headers: { authorization: `Bearer ${API_KEY}`, 'content-type': 'application/json' }, body: JSON.stringify({ agentId, ttlSec: 300, ops: ['publish', 'history'], channels: CHANNELS }) }); res.writeHead(r.status, { ...cors, 'content-type': 'application/json' }).end(JSON.stringify({ ...(await r.json()), agentId, channels: CHANNELS })); }).listen(PORT, '127.0.0.1', () => console.log(`token server on http://127.0.0.1:${PORT}/token (channels ${CHANNELS.join(',')})`));