How to Configure the Speech-to-Speech Server for Production Deployment with Authentication

The Hugging Face Speech-to-Speech demo server enables production authentication and usage limits by deploying as a Hugging Face Space with OAuth enabled, setting LOAD_BALANCER_URL and SPACE_ID environment variables, and letting demo/auth.py and demo/server.py automatically wire Hugging Face OAuth and tier-based metering.

Running the Hugging Face Speech-to-Speech demo in production requires more than starting the FastAPI server locally. When deployed as a Hugging Face Space, the repository provides built-in authentication, per-user rate limiting, and organization-based tier resolution. This guide explains how to configure the speech-to-speech server for production deployment with authentication using the actual source code implementation.

How Production Authentication Works

The authentication system activates only when both LOAD_BALANCER_URL and SPACE_ID environment variables are present. This safety mechanism ensures OAuth and metering never interfere with local development.

Core Components

Component File Responsibility
OAuth handler demo/auth.py Implements Hugging Face OAuth, resolves user tiers (pro, org, free), mints anonymous cookies
Server entry point demo/server.py Calls auth.attach(app) during startup, exposes /api/me endpoint
Usage limiter demo/limiter.py Stores per-user daily counters, enforces budgets, signs/verifies anonymous cookies

In demo/server.py, the following logic gates all production features:


# server.py (excerpt)

LIMITER_ENABLED = bool(LOAD_BALANCER_URL) and bool(SPACE_ID)

# Wire HF OAuth before the app serves (no-op unless the OAuth env is present).

# Sign-in only matters when we're metering (prod Space), so gate it on that.

AUTH_ENABLED = LIMITER_ENABLED and auth.attach(app)

When AUTH_ENABLED evaluates to True, the server exposes /api/me and protects the WebRTC signaling endpoints with tier-aware usage budgets.

Required Environment Variables

Configure these variables in your Space's Settings → Environment variables:

Variable Purpose Required
LOAD_BALANCER_URL URL of the Speech-to-Speech load balancer; triggers metered, sign-in-aware mode Yes for production
SPACE_ID Identifier of the Space (owner/space); auto-injected by Hugging Face platform Yes (auto-provided)
OAUTH_CLIENT_ID Enables Hugging Face OAuth flow; auto-provided when hf_oauth: true is in README Auto-provided
SERPER_API_KEY API key for the Google search proxy (/api/search) Optional
RTC_ICE_SERVERS JSON list of ICE servers for WebRTC behind strict firewalls Optional
UNLIMITED_ORGS Comma/space-separated org usernames with unlimited usage Optional

These are read in demo/server.py (lines 60–82) and demo/auth.py (lines 38–46, 66–70).

Step-by-Step Production Deployment

1. Build the Container

The repository includes a root Dockerfile that installs the package and copies the demo/ directory:

FROM python:3.11-slim

COPY . /app
WORKDIR /app
RUN pip install --no-cache-dir .[all]

EXPOSE 7860
CMD ["uvicorn", "demo.server:app", "--host", "0.0.0.0", "--port", "7860"]

Build and test locally:

docker build -t s2s-demo .
docker run -p 7860:7860 s2s-demo

2. Create and Configure the Hugging Face Space

Add hf_oauth: true to your Space's README.md:


# Speech-to-Speech Demo

hf_oauth: true

Push your code to the Space. The platform automatically injects OAUTH_CLIENT_ID and SPACE_ID.

3. Set Production Environment Variables

In the Space's Settings → Environment variables, add:

Name Example Value
LOAD_BALANCER_URL https://lb.my-company.com
SERPER_API_KEY sk_... (if using search)
RTC_ICE_SERVERS [{"urls":"turn:turn.example.com:3478","username":"user","credential":"pass"}]
UNLIMITED_ORGS my-org enterprise-team

The server starts with authentication enabled when LOAD_BALANCER_URL and SPACE_ID are both present.

4. Bypass Authentication for Direct S2S Access (Optional)

Set SPEECH_TO_SPEECH_URL to a direct backend URL. When non-empty, this disables all load-balancer, limiter, and authentication logic:

export SPEECH_TO_SPEECH_URL="wss://direct-backend.example.com"

Use this for internal deployments where you handle authentication upstream.

How Authentication Is Enforced at Runtime

The /api/me Endpoint

Once AUTH_ENABLED is true, the server exposes:


# server.py excerpt

@app.get("/api/me")
async def me(request: Request) -> dict:
    if not AUTH_ENABLED:
        return {"enabled": False}
    # Returns: {enabled: true, loggedIn: bool, tier: str, remaining: int, reason: str?}

    return auth.user_view(request)

Call this from your client to display login status and remaining budget:

fetch("/api/me")
  .then(r => r.json())
  .then(info => {
    if (!info.enabled) {
      console.log("Local mode – no authentication");
      return;
    }
    console.log("Logged in:", info.loggedIn);
    console.log("Tier:", info.tier);        // "pro", "org", "free", "anon"
    console.log("Remaining:", info.remaining);
  });

Identity Resolution and Tier Assignment

When a protected request arrives, demo/server.py calls auth.resolve_identity:


# auth.py excerpt

async def resolve_identity(request: Request) -> tuple[str, list[str], str | None]:
    # Returns: (tier, keys, set_cookie_header)
  • Signed-in users: Tier derived from auth.resolve_tier via org membership or PRO status
  • Anonymous users: ANON_COOKIE minted and signed with limiter.sign_cookie

The keys returned are hashed via limiter.hash_key and used to debit daily budgets. Exceeded budgets yield HTTP 429.

Optional: Grant Unlimited Access to Organizations

Add organization slugs to UNLIMITED_ORGS for internal teams:

export UNLIMITED_ORGS="huggingface my-research-lab"

Members of these organizations bypass all usage limits while still requiring authentication.

Key Files Reference

File Lines Purpose
demo/auth.py 38–46, 66–90 OAuth flow, tier resolution, cookie handling
demo/server.py 60–82, 100–120 Environment parsing, auth.attach(), /api/me
demo/limiter.py 20–50 Budget enforcement, cookie signing
Dockerfile 1–12 Production container definition

Summary

  • Deploy as a Hugging Face Space with hf_oauth: true in README.md to enable OAuth
  • Set LOAD_BALANCER_URL to trigger production authentication and metering
  • SPACE_ID and OAUTH_CLIENT_ID are auto-injected by the platform
  • SPEECH_TO_SPEECH_URL bypasses all auth for direct backend access
  • Optional variables (SERPER_API_KEY, RTC_ICE_SERVERS, UNLIMITED_ORGS) extend functionality

The demo/auth.py and demo/server.py implementation ensures authentication only activates when both infrastructure variables are present, protecting local development from accidental lockout.

Frequently Asked Questions

What happens if I don't set LOAD_BALANCER_URL?

The server runs in local development mode. LIMITER_ENABLED evaluates to False, AUTH_ENABLED becomes False, and all endpoints remain unauthenticated with no usage limits. This is the safe default for testing.

Can I use authentication without Hugging Face Spaces?

No. The OAuth implementation in demo/auth.py specifically targets Hugging Face's OAuth provider. The auth.attach(app) function expects OAUTH_CLIENT_ID in the format provided by Spaces. For non-Space deployments, implement custom authentication or use SPEECH_TO_SPEECH_URL with an upstream proxy.

How do anonymous cookies prevent abuse?

Anonymous users receive a salted, signed cookie (ANON_COOKIE) via limiter.sign_cookie. The signature verification in demo/limiter.py prevents cookie tampering, and the hash-based key derivation ensures each anonymous session has isolated usage tracking without requiring login.

What tiers exist and how are they assigned?

The auth.resolve_tier function assigns:

  • pro — User has an active Hugging Face PRO subscription
  • org — User belongs to an organization with either enterprise features or listing in UNLIMITED_ORGS
  • free — Authenticated user without PRO or special org status
  • anon — Unauthenticated user with cookie-based tracking

Have a question about this repo?

These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:

Share the following with your agent to get started:
curl -s "https://instagit.com/install.md"

Works with
Claude Codex Cursor VS Code OpenClaw Any MCP Client

Maintain an open-source project? Get it listed too →