Header Logo

How to Authenticate Users Before Starting a Voice + Video Shopping Avatar in React and Next.js

How to Authenticate Users Before Starting a Voice + Video Shopping Avatar in React and Next.js

Authenticate users server-side before starting a voice/video shopping avatar in React and Next.js; mint short-lived realtime session tokens.

Introduction


If you are adding a voice-and-video shopping avatar to a React + Next.js app, the authentication problem is not “how do I show a face on screen?” It is “how do I make sure the right user is allowed to start a realtime session, and how do I keep secrets out of the browser while doing it?”


That matters because a shopping avatar typically has state: the user identity, permissions, cart context, language, maybe a conversation history or product scope. The avatar session should only start after your app has authenticated the user, authorized the action, and attached whatever session metadata your backend needs to enforce policy.


By the end of this post, you should be able to design the flow correctly in Next.js: authenticate the user in your app, mint a short-lived session token or server-side grant, then start the avatar only after your backend approves it. You will also see where a developer-facing realtime avatar API like Protoface fits into that architecture.


The core rule: never start the avatar from an unauthenticated browser context


A browser client should not contain your avatar API key, and it should not be allowed to create arbitrary sessions directly against a privileged control plane. The browser can initiate UI actions; the server should decide whether the user is allowed to start the experience.


For a shopping avatar, that usually means:


  1. The user signs in to your app with your normal auth system.

  2. The client requests “start avatar session” from your Next.js backend.

  3. The backend verifies the logged-in user and checks business rules.

  4. The backend creates or authorizes a realtime avatar session using server credentials.

  5. The backend returns only the minimal session data the browser needs to connect.


This is the same pattern you would use for WebRTC, chat, or payment flows: browser gets an ephemeral result, backend holds the authority.


What “authentication before start” should actually enforce


At minimum, your backend should answer three questions before a session begins:


  • Who is the user? Resolve the authenticated principal from your app session or JWT.

  • Is this user allowed to start a session? Check plan, account status, rate limits, and feature flags.

  • What context can be attached to the session? Pass safe metadata only: tenant ID, locale, product category, cart ID, or a conversation policy. Do not pass secrets or anything the model should not see.


For shopping flows, “allowed” often also includes product availability, region restrictions, and whether the user is already in an active session. You want those checks server-side because the client is easy to tamper with.


A practical Next.js flow


The cleanest implementation is usually:


  1. Use your standard Next.js auth layer for login.

  2. Expose a server route like POST /api/avatar-session.

  3. Have that route require authentication.

  4. Inside the route, validate the request, authorize it, and create the avatar session with server credentials.

  5. Return a short-lived session payload to the client.


The client then mounts the avatar component only after it has that session payload.


// app/api/avatar-session/route.ts

}
// app/api/avatar-session/route.ts

}
// app/api/avatar-session/route.ts

}


The exact payload depends on your avatar provider’s session model, but the architectural shape does not: authenticate first, authorize server-side, then hand the browser a time-limited credential or connection descriptor.


Why this matters specifically for realtime video avatars


Realtime avatars are not static images. They are usually backed by streaming media and a conversational pipeline. In practice, the browser may be receiving a live video track, audio track, or a rendered stream from a session that also connects to speech recognition, an LLM, and text-to-speech. Once that session is live, it can consume compute and billable usage.


So the failure modes are more expensive than a simple UI bug:


  • Unauthenticated users can generate cost.

  • One account can be used to start many parallel sessions unless you rate-limit.

  • Client-side secrets can be extracted and reused elsewhere.

  • Session metadata can be forged if you trust the browser too much.


That is why session creation should be tied to your own auth boundary, not just to a button click. If you want “guest” access, treat it as a deliberate product decision and still issue a constrained, short-lived grant from the backend.


Client-side mounting in React: wait for the grant, then connect


In the component tree, keep session creation and session use separate. The UI can collect intent, but the actual start happens only after the server responds. This avoids accidental double-starts and makes it easy to surface authorization errors cleanly.


"use client";

}
"use client";

}
"use client";

}


In a real app, the next step after setSession is usually to mount the video avatar component, WebRTC client, or iframe/embed widget using the returned ephemeral data. Keep the token in memory only; do not persist it to localStorage unless the provider explicitly expects a long-lived credential, which is uncommon for realtime sessions.


Authorization details that developers often miss


Authentication proves identity. Authorization decides what that identity is allowed to do. For a shopping avatar, useful checks include:


  • Tenant scope: the user can only start a session for their organization or storefront.

  • Rate limits: cap session starts per user, per IP, or per account.

  • Concurrency: prevent duplicate sessions from the same user if your UX assumes one active agent at a time.

  • Locale and channel policy: attach only approved languages, voices, or custom instructions.

  • Conversation scope: decide whether the avatar can discuss all products or only a subset.


If the session will hand off to a fulfillment backend, make sure the avatar only gets identifiers that are safe to expose. For example, a cart ID is usually fine if it is already scoped to the authenticated user; a payment token is not.


Where Protoface fits


This is the kind of flow the docs are built for: your Next.js backend keeps the API key, creates or manages the realtime session server-side, and your browser receives only the minimal data needed to connect. That matches the REST API and Python SDK model, where requests are authenticated with an API key like Authorization: Bearer sk_live_..., and it also matches the LiveKit agent path if your shopping assistant is already built as a voice agent.


# Illustrative REST call from your server, not the browser
-d '{"name":"shopping-assistant","quality_tier":"..."}'
# Illustrative REST call from your server, not the browser
-d '{"name":"shopping-assistant","quality_tier":"..."}'
# Illustrative REST call from your server, not the browser
-d '{"name":"shopping-assistant","quality_tier":"..."}'


In a LiveKit-based architecture, your server-side agent can use the Protoface plugin to give the voice agent a synchronized talking face. The important part is that the user is authenticated before your backend starts the session or attaches the avatar. The browser should never see the API key, only the result of your authorization check.


# Example shape only; see the plugin repo and docs for exact setup

)
# Example shape only; see the plugin repo and docs for exact setup

)
# Example shape only; see the plugin repo and docs for exact setup

)


If you prefer a quick starting point, the relevant integration examples are in the plugin repository and quickstarts, but the security model stays the same regardless of transport: authenticate the user first, then create the realtime avatar session server-side.


Implementation gotchas in Next.js


A few issues show up repeatedly:


  • Client components triggering session creation twice: guard against double clicks and React re-renders.

  • Stale auth state: always verify the user on the server route, not just in the UI.

  • Leaking privileged keys: API keys belong in server env vars only.

  • Long-lived browser tokens: prefer short-lived session credentials for realtime connections.

  • Premature avatar startup: do not connect the media pipeline until the server grants it.


A good test is simple: if someone opens DevTools, can they start arbitrary avatar sessions or reuse a token from another account? If the answer is yes, the boundary is wrong.


Conclusion


For a voice + video shopping avatar, the right pattern is straightforward: authenticate the user in your Next.js app, authorize the request on the server, create the realtime session server-side, and give the browser only an ephemeral result. That keeps your API keys private, reduces abuse, and lets you attach clean session context for the shopping flow.


If you are building this against a realtime avatar platform, start with the docs, wire the backend boundary first, and then connect the React UI to the server-issued session. For the exact request shapes and integration details, see docs.protoface.com and the relevant quickstart repos linked from the project README.

Add a face to your AI.

No credit card needed.

Add a face to your AI.

No credit card needed.

Add a face to your AI.

No credit card needed.