Use ephemeral client secrets for browser Realtime sessions
A secure browser pattern for starting Realtime sessions without exposing your OpenAI API key.
Open source docReal workflow example
A browser-based voice intake screen needs to connect directly to a realtime model for low-latency audio. The tempting shortcut is to put the OpenAI API key in a client environment variable and connect from the browser. That works in a demo and fails as a security design.
The proper pattern is server-issued ephemeral credentials. The browser asks your app server to start a session. The server authenticates the user, checks workflow access, creates the scoped realtime session, and returns only a short-lived client secret.
Implementation approach
Treat session creation as a protected backend action. The server should know who is starting the session, which organization or workspace they belong to, what workflow they are allowed to run, and what session policy applies.
The browser should receive only the temporary credential and the minimal connection details it needs. Business actions still go through server routes or tools that validate authorization. When the call ends, clear local session state and mark the intake as complete, abandoned, or escalated.
Code or config snippet
// app/api/realtime/session/route.ts
export async function POST(request: Request) {
const user = await requireUser(request);
const body = await request.json();
await assertCanStartVoiceIntake(user.id, body.workspaceId);
const session = await openai.realtime.sessions.create({
model: "gpt-4o-realtime-preview",
voice: "alloy",
instructions:
"Collect intake facts. Do not make pricing commitments. Escalate when unsure.",
});
return Response.json({
clientSecret: session.client_secret.value,
expiresAt: session.client_secret.expires_at,
});
}
Mistakes to avoid
- Do not expose the long-lived OpenAI API key in a public environment variable.
- Do not create realtime sessions before checking user access.
- Do not put privileged business tools directly in browser code.
- Do not reuse the same client secret across users or workflows.
- Do not ignore expiration and cleanup states in the UI.
Ready checklist
- Server route authenticates the current user.
- Authorization checks the workspace and workflow.
- Browser receives only a short-lived client secret.
- Realtime instructions are scoped to the workflow.
- Business actions remain server-side.
- Session end and failure states clean up local state.
Practical tip
Log safe session metadata on the server: user ID, workspace ID, workflow name, session ID, start time, and end state. Do not log tokens, audio, or raw sensitive transcript text unless your retention policy explicitly allows it.
