Header Logo

How to Secure Realtime AI Avatar APIs for In-App SaaS Help

How to Secure Realtime AI Avatar APIs for In-App SaaS Help

Secure realtime AI avatar APIs with server-side secrets, short-lived tokens, origin checks, rate limits, and tenant-scoped embeds.

Introduction


Realtime AI avatars are just another distributed system problem wearing a nicer face. You still have to secure the control plane, constrain browser exposure, validate who can create sessions, and make sure any streaming surface is scoped tightly enough that a stolen token or bad embed cannot turn into an expensive incident.


This matters more for in-app SaaS help than for a demo. Once an avatar sits inside a support flow, it can see authenticated users, respond with product-specific instructions, and potentially trigger costly realtime media sessions. By the end of this post, you should have a practical model for securing avatar APIs and embeds: where to keep secrets, how to issue short-lived access, what to allow in the browser, and how to think about rate limits and tenant isolation.


Start with the trust boundaries


The first mistake is treating a realtime avatar like a static widget. It is not. There are usually three distinct surfaces:


  • Server-side control plane for creating avatars, sessions, and configuration.

  • Realtime media plane for the actual voice/video exchange, usually over WebRTC or a similar streaming transport.

  • Browser embed or client SDK that initiates or joins the session.


Each surface has different security properties. The control plane should require a real secret and never be reachable from untrusted browsers. The media plane should be scoped to a specific session, with time-bound credentials and a clear origin model. The browser surface should expose as little as possible: ideally only an opaque session URL or token with narrow permissions.


If you’re building help inside a SaaS app, the right question is not “can the user see the avatar?” It’s “what can this user or page do, for how long, and on whose bill?” Those are the boundaries that matter operationally.


Never ship a long-lived API key to the browser


This is the obvious one, but it still shows up in code reviews. Your management API key is for your backend only. A key like Authorization: Bearer sk_live_... should be treated as a privileged credential with full account-level blast radius. If it leaks into frontend code, you’ve effectively handed out write access to avatars, sessions, usage, and possibly billing-relevant actions.


The fix is straightforward:


  1. Keep the API key only in server-side environment variables or a secret manager.

  2. Have your backend create whatever short-lived session artifact the browser needs.

  3. Return only that narrow artifact to the client.


A minimal creation flow against the REST API looks like this from your backend:


curl -X POST https://api.protoface.com/v1/sessions \
}'
curl -X POST https://api.protoface.com/v1/sessions \
}'
curl -X POST https://api.protoface.com/v1/sessions \
}'


The exact request shape belongs in the docs, but the security pattern is the important part: the browser should never need your secret. It should only receive the minimum token or session handle needed to join the realtime interaction.


Use short-lived, per-session authorization


Realtime systems fail closed only if the credentials are scoped tightly. In practice, you want session-level authorization rather than account-level authorization. That usually means:


  • Short expiration times, measured in minutes or a small number of hours.

  • Single-purpose tokens: one token, one avatar session, one tenant.

  • Revocation support if the customer ends the interaction or logs out.

  • Explicit claims or metadata that bind the session to a user, workspace, or support ticket.


This matters because realtime media is not just a one-shot API call. Once a session is active, it can stream audio/video for as long as the token remains valid. If you mint broad or long-lived tokens, the damage from leakage increases quickly, both in terms of access and usage cost.


There’s also a practical reliability angle. Session-specific credentials make your backend state easier to reason about. If a user opens two support tabs, you can decide whether that should create two independent avatar sessions or whether one should invalidate the other. Either way, you can enforce it server-side.


Validate origin, tenant, and intent before you create anything


Whether you expose a REST endpoint for avatar sessions or an embed bootstrap flow, treat session creation as an authenticated business action, not a generic public endpoint. For an in-app support flow, your backend should verify all of the following before it calls the avatar service:


  • The user is authenticated in your app.

  • The user is authorized for the specific tenant or workspace.

  • The request is tied to a legitimate UI event, such as opening support chat.

  • The requested avatar configuration is allowed for that tenant.


For web apps, origin checks matter too. If you are issuing a browser-facing token or iframe bootstrap data, validate the request origin against your allowlist and reject unexpected origins. That does not replace authentication, but it stops a lot of accidental token reuse and embed abuse.


Keep the avatar configuration server-authored. A user should not be able to choose arbitrary instructions, voices, or model settings unless that is a deliberate product feature. Otherwise you end up with prompt injection through configuration, not just through conversation content.


Apply rate limits at the edges that can cost you money


Realtime avatar sessions are a cost center. You should rate limit at more than one layer:


  • Creation rate: how many sessions a user, org, or IP can open in a window.

  • Concurrency: how many active sessions a tenant can hold at once.

  • Duration: how long a session can stay open before it expires or requires renewal.

  • Replay resistance: prevent the same session bootstrap from being reused across clients.


This is especially important for in-app SaaS help, where abuse often looks like “refresh until the bot appears” or “open a hundred tabs.” Even if the traffic is not malicious, unbounded session creation can produce noisy usage spikes.


Per-IP limits help at the public edge, but they are not enough on their own. In authenticated SaaS, you also want per-user and per-tenant controls because multiple legitimate users can share an IP, and one user can generate many IPs. When the session is meant to live inside a specific customer account, the tenant should be the primary quota boundary.


Keep prompt and instruction surfaces server-owned


Security for avatar APIs is not only about secrets. It is also about who gets to tell the avatar what to say. In support or help flows, the model instructions should come from your server, ideally assembled from controlled templates and product metadata. Do not let the browser send arbitrary free-form instructions unless you are intentionally building a user-customizable experience.


The reason is simple: prompt content is an input to behavior, and behavior can drive cost, compliance exposure, or harmful responses. If the avatar is supposed to explain your billing policy, then the browser should request “billing-help avatar session,” not “here is my own custom persona and policy override.”


A good pattern is:


# pseudo-code
)
# pseudo-code
)
# pseudo-code
)


That keeps policy decisions on the backend where you can audit them.


How a secure embed changes the browser problem


If you want the simplest browser story, use a customer-managed iframe embed. The security benefit is that the embed can be configured so the parent page never sees your API key, and the browser does not need privileged backend access at all. That shrinks the attack surface substantially compared with a custom frontend integration.


For an in-app SaaS help use case, this is attractive when you want a lightweight launch path with sane defaults: parent-origin allowlisting, per-embed voice and instructions, plus per-IP and duration limits. In other words, the browser gets a narrowly scoped media experience, not a general-purpose API client.


That does not mean you can ignore authentication. You still need to decide which authenticated users are allowed to load the embed, and you should keep any tenant-specific configuration on your side. But you no longer have to solve the “secret in the browser” problem, which is usually where teams get into trouble first.


Where Protoface fits in practice


For developers already using Protoface, the security model above maps cleanly onto the platform surfaces. The REST API and Python SDK are the right place for server-side session creation and management, while the customer-managed iframe is useful when you want to avoid exposing any API key in the browser. If you are integrating into a voice stack, the LiveKit plugin can attach a synchronized video face to a voice agent without changing your broader auth model.


In Python, keep the SDK call on the backend and return only a session artifact to the client:


from protoface import Client

return {"session_id": session.id}
from protoface import Client

return {"session_id": session.id}
from protoface import Client

return {"session_id": session.id}


For LiveKit-based agents, the same principle applies: the plugin should be fed from trusted server-side configuration, not directly from user input. If you want examples and exact request fields, use the docs and quickstarts rather than guessing at payload shapes.


Useful references: the docs for API and embed behavior, the Python SDK repository for server-side examples, and the OpenAI Realtime quickstart if you’re wiring avatar output into an existing voice-agent stack.


Conclusion


Securing a realtime avatar API is mostly about disciplined scoping. Keep secrets server-side, mint short-lived session credentials, validate origin and tenant before creating anything, and rate limit at the points where abuse turns into cost. Treat instructions as server-owned policy, not browser input. If you do that, adding a talking face to an in-app help flow becomes a normal integration problem instead of a security surprise.


If you want implementation details, start with the public docs at docs.protoface.com, then wire up a backend-only session flow and test it with one tenant and one short-lived token. That’s usually enough to flush out the real edge cases before you ship to production.

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.