Rate Limiting and Authentication for Production Deployment in Hugging Face Speech-to-Speech

The speech-to-speech repository provides stateless authentication and tier-based rate limiting through demo/auth.py and demo/limiter.py, automatically activating when deployed as a Hugging Face Space to enforce daily talk-time budgets without external databases.

The huggingface/speech-to-speech demo is designed for production deployment on Hugging Face Spaces, where protecting compute resources from abuse is critical. The codebase implements a dual-layer protection system that handles user identification through OAuth and token validation while enforcing daily usage caps based on user tiers. Rate limiting and authentication for production deployment are handled entirely within the FastAPI application layer, requiring only environment variables and Space secrets to configure.

Architecture Overview

The production protection stack consists of two independent subsystems wired into the FastAPI server in demo/server.py:

  • demo/auth.py – Handles OAuth flows, token extraction, and user tier resolution via functions like attach(), current_access_token(), and resolve_identity().
  • demo/limiter.py – Manages daily talk-time budgets through budget_for() and per-session bookkeeping logic.

When the server starts, it detects whether it is running inside a Hugging Face Space by checking for the presence of SPACE_ID and LOAD_BALANCER_URL. If both are present, the limiter and auth subsystems are enabled:


# demo/server.py

LIMITER_ENABLED = bool(LOAD_BALANCER_URL) and bool(SPACE_ID)
AUTH_ENABLED = LIMITER_ENABLED and auth.attach(app)

Authentication Flow

The authentication system is deliberately stateless, relying on JWT tokens and in-memory caching rather than persistent user databases.

OAuth Activation

If the environment variable HF_OAUTH is set to "true", the auth.attach(app) function registers Hugging Face OAuth endpoints by calling huggingface_hub.attach_huggingface_oauth(app). This adds the /oauth/huggingface/* routes to the FastAPI application, allowing users to authenticate via their Hugging Face accounts.

Token Extraction and Identity Resolution

For every incoming request, the system extracts and validates credentials through a three-step process:

  1. Token extraction – current_access_token(request) reads the Authorization header or the OAuth cookie set by the login flow, returning a stripped token string or None.
  2. Identity resolution – resolve_identity(request) uses the token to look up the user's tier, API keys, and any "unlimited-org" status. It returns a tuple of (tier, keys, set_cookie_flag).
  3. User view – user_view(request) constructs a JSON response sent to the client containing UI hints such as auth, tier, and loginUrl.

Rate Limiting Implementation

The rate limiter prevents resource exhaustion by tracking talk-time consumption against daily quotas defined per user tier.

Tier-Based Budgets

The budget_for(tier) function in demo/limiter.py returns the daily second-budget for the given tier as an integer, or None for unlimited access. Budget mappings are loaded from the S2S_BUDGETS Space secret (JSON format) and fall back to a temporary file under /tmp if the secret is unavailable.

Session Accounting

When a new realtime session is created, the server initializes a SQLite database (stored under /data) to track remaining allowance for that specific session. Every 5 seconds, the server reports a budget chunk (CHUNK_SEC) that the client may consume. The limiter subtracts used time from the stored budget and returns False once the daily quota is exhausted, prompting the client to terminate the session.

The limiter employs conservative accounting: it uses the maximum of "seconds spent on the current session identifier" and "seconds spent on the same user key" to prevent users from resetting their budget by opening new sessions.

Deploy-Time Configuration

Configure these environment variables to activate production protection:

Variable Purpose Example Value
HF_SPACE_ID Space identifier (set automatically on Hugging Face) username/space-name
LOAD_BALANCER_URL External load balancer URL required for rate limiting https://lb.huggingface.co
HF_OAUTH Enable OAuth flow true
S2S_BUDGETS JSON mapping of tier to daily seconds {"anonymous": 300, "signed_in": 1800, "pro": null}
UNLIMITED_ORGS Comma-separated organization IDs with unlimited budget org-abc,org-xyz

Implementation Examples

Enabling Protection in Custom Deployments

To manually enable authentication and rate limiting outside of Hugging Face Spaces:

from fastapi import FastAPI
from demo import auth, limiter
import os

app = FastAPI()

if bool(os.getenv("LOAD_BALANCER_URL")) and bool(os.getenv("HF_SPACE_ID")):
    auth.attach(app)          # Registers OAuth routes & token parsing

    limiter_enabled = True   # Signal to server routes

else:
    limiter_enabled = False

Resolving User Identity in Endpoints

Extract the user's tier and API keys within any route:

from fastapi import Request, APIRouter
from demo import auth

router = APIRouter()

@router.get("/whoami")
def whoami(request: Request):
    tier, keys, _ = auth.resolve_identity(request)
    return {"tier": tier, "api_keys": keys}

Checking Remaining Budget

Validate whether a user has talk-time remaining before processing:

from demo import limiter

def is_allowed(tier: str) -> bool:
    # Returns True if daily budget is not exhausted

    remaining = limiter.budget_for(tier)
    return remaining is None or remaining > 0

Client-Side Authentication

Connect to the API using personal access tokens:

import httpx

token = "hf_aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
headers = {"Authorization": f"Bearer {token}"}

async with httpx.AsyncClient() as client:
    resp = await client.post(
        "https://my-space.hf.space/api/session", 
        headers=headers
    )
    # Server resolves token → tier → budget automatically

Summary

  • Authentication is handled statelessly in demo/auth.py via OAuth and Bearer tokens, requiring no external database.
  • Rate limiting tracks daily talk-time budgets per tier in demo/limiter.py, using SQLite for per-session bookkeeping under /data.
  • Automatic activation occurs when LOAD_BALANCER_URL and HF_SPACE_ID are present, making the system ideal for serverless Space deployments.
  • Conservative accounting prevents budget circumvention by tracking both session identifiers and user keys.
  • Configuration relies entirely on environment variables and Space secrets (S2S_BUDGETS, UNLIMITED_ORGS).

Frequently Asked Questions

How does the server detect it is running in a Hugging Face Space?

The server checks for the presence of both SPACE_ID and LOAD_BALANCER_URL environment variables at startup in demo/server.py. When both are present, it sets LIMITER_ENABLED = True and attempts to attach the authentication handlers.

What happens when a user exhausts their daily budget?

Once the budget_for() function returns a value of zero or the per-session SQLite tracker reaches zero, the limiter returns False to the server. The server then signals the client to shut down the session, terminating the connection until the next daily reset.

Can organizations bypass rate limiting entirely?

Yes. Organization IDs listed in the UNLIMITED_ORGS environment variable receive a None response from budget_for(), causing the limiter to skip all accounting. Similarly, tiers mapped to null in the S2S_BUDGETS JSON configuration receive unlimited access.

Is a database required to store user sessions or budgets?

The authentication system is completely stateless and requires no database. However, the rate limiter uses a lightweight SQLite database stored under /data strictly for per-session bookkeeping of remaining talk-time, not for storing user profiles or credentials.

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 →