How to Set Up API Authentication with Token-Based Security in Fish Speech

Secure your Fish Speech API by launching the server with --api-key <token> and sending requests with the Authorization: Bearer <token> header.

Fish Speech provides a production-ready HTTP API server that supports token-based authentication via Bearer tokens. This security layer is implemented as ASGI middleware in the inference server, allowing you to protect text-to-speech endpoints without modifying your client code beyond adding a header. The authentication flow is defined in the server utilities and enforced globally across all routes when enabled.

How Token-Based Authentication Works in Fish Speech

The authentication system uses a simple but effective shared secret pattern. When you start the server with a specific token, the middleware intercepts every incoming request and validates the Authorization header against that secret.

The flow works as follows:

  1. Server startup: You provide a token via the --api-key argument in tools/server/api_utils.py
  2. Middleware activation: The api_auth function in tools/api_server.py wraps all routes with a verification layer
  3. Request validation: Clients must include Authorization: Bearer <your-token> in every request header
  4. Access control: If the token mismatches or is missing, the server returns HTTP 401 Unauthorized

If you omit the --api-key flag during startup, the server automatically disables authentication and accepts all requests.

Configuring the API Key on the Server

Command-Line Setup

The server accepts your authentication token through a command-line argument defined in tools/server/api_utils.py (lines 21-42):

parser.add_argument("--api-key", type=str, default=None)

To enable authentication, launch your server with the --api-key flag:

python tools/api_server.py \
  --llama-checkpoint-path checkpoints/s2-pro \
  --decoder-checkpoint-path checkpoints/s2-pro/codec.pth \
  --listen 0.0.0.0:8080 \
  --api-key mySuperSecret123

Important: Choose a cryptographically secure random string for production environments. The token is stored in memory only and never written to disk unless you include it in your startup scripts.

Understanding the Authentication Middleware

The enforcement logic resides in tools/api_server.py (lines 33-45) within the api_auth function:

def api_auth(endpoint):
    async def verify(token: Annotated[str, Depends(bearer_auth)]):
        if token != self.args.api_key:
            raise HTTPException(401, None, "Invalid token")
        return await endpoint()
    
    if self.args.api_key is not None:
        return verify
    else:
        return passthrough

This middleware performs three critical functions:

  1. Token extraction: Uses bearer_auth dependency to parse the Authorization header
  2. Constant-time comparison: Compares the provided token against self.args.api_key (the value from your --api-key argument)
  3. Error handling: Returns HTTP 401 with "Invalid token" if verification fails

All routes—including /v1/tts and /v1/vqgan/encode—are automatically wrapped with this middleware when you provide an API key:

self.routes = Routes(routes, http_middlewares=[api_auth])

Making Authenticated Requests

Once the server is running with authentication enabled, every client request must include the Bearer token in the HTTP headers.

Using curl

TOKEN=mySuperSecret123

curl -X POST http://127.0.0.1:8080/v1/tts \
     -H "Authorization: Bearer $TOKEN" \
     -H "Content-Type: application/msgpack" \
     --data-binary @request.msgpack \
     --output audio.wav

Using the Python Client

Fish Speech provides a reference client in tools/api_client.py (lines 80-84) that automatically handles authentication when you provide the --api_key argument:

headers={
    "authorization": f"Bearer {args.api_key}",
    "content-type": "application/msgpack",
}

Run the client with:

python tools/api_client.py \
    --text "Hello from Fish Speech!" \
    --api_key mySuperSecret123 \
    --url http://127.0.0.1:8080/v1/tts \
    --format wav

Disabling Authentication for Local Development

For local testing or internal networks where security is not a concern, you can run the server without the --api-key flag:

python tools/api_server.py \
  --llama-checkpoint-path checkpoints/s2-pro \
  --decoder-checkpoint-path checkpoints/s2-pro/codec.pth \
  --listen 127.0.0.1:8080

When args.api_key is None, the api_auth middleware returns a passthrough function that immediately forwards requests to the endpoint without validation.

Summary

  • Token-based security in Fish Speech is enabled by starting the server with --api-key <token> in tools/server/api_utils.py
  • The authentication middleware in tools/api_server.py enforces Bearer token validation on every route, returning HTTP 401 for invalid or missing tokens
  • Clients must include Authorization: Bearer <token> headers, as demonstrated in tools/api_client.py
  • Omitting --api-key disables authentication entirely, creating a passthrough middleware suitable for local development

Frequently Asked Questions

What happens if I don't provide the Authorization header?

If the server was started with --api-key and you omit the Authorization: Bearer <token> header, the middleware in tools/api_server.py will raise an HTTPException with status code 401 and the message "Invalid token", rejecting your request before it reaches the TTS endpoint.

Can I use multiple API keys?

The current implementation in tools/api_server.py only supports a single shared secret via the --api-key argument. If you need multiple keys for different clients, you would need to modify the verify function in the api_auth middleware to check against a list or database of valid tokens instead of a single self.args.api_key value.

Is the token transmitted securely?

Security depends on your transport layer. The Fish Speech server itself handles the token in plaintext memory (comparing token != self.args.api_key in tools/api_server.py). To prevent interception, always run the server behind HTTPS/TLS in production environments, ensuring the Authorization header is encrypted during transit.

Where is the API key stored?

The API key is not stored persistently by the Fish Speech server. It exists only in memory as self.args.api_key after being parsed from the command line in tools/server/api_utils.py. If you restart the server without the --api-key flag, the previous token becomes invalid and authentication is disabled.

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 →