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_tiervia org membership or PRO status - Anonymous users:
ANON_COOKIEminted and signed withlimiter.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: truein README.md to enable OAuth - Set
LOAD_BALANCER_URLto trigger production authentication and metering SPACE_IDandOAUTH_CLIENT_IDare auto-injected by the platformSPEECH_TO_SPEECH_URLbypasses 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 subscriptionorg— User belongs to an organization with either enterprise features or listing inUNLIMITED_ORGSfree— Authenticated user without PRO or special org statusanon— 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:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →