> ## Documentation Index

> Fetch the complete documentation index at: /llms.txt

> Use this file to discover all available pages before exploring further.

Skip to main content
Authentication

# Multiple Auth Sources

Accept tokens from multiple authentication sources with a single server.

New in version `3.1.0` Production servers often need to accept tokens from multiple authentication sources. An interactive application might authenticate through an OAuth proxy, while a backend service sends machine-to-machine JWT tokens directly. `MultiAuth` composes these sources into a single `auth` provider so every valid token is accepted regardless of where it was issued.

##
​
Understanding MultiAuth

`MultiAuth` wraps an optional auth server (like `OAuthProxy`) together with one or more token verifiers (like `JWTVerifier`). When a request arrives with a bearer token, `MultiAuth` tries each source in order and accepts the first successful verification. The auth server, if provided, is tried first. It owns all OAuth routes and metadata — the verifiers contribute only token verification logic. This keeps the MCP discovery surface clean: one set of routes, one set of metadata, multiple verification paths.

    from fastmcp import FastMCP
    from fastmcp.server.auth import MultiAuth, OAuthProxy
    from fastmcp.server.auth.providers.jwt import JWTVerifier

    auth = MultiAuth(
        server=OAuthProxy(
            issuer_url="https://login.example.com/...",
            client_id="my-app",
            client_secret="secret",
            base_url="https://my-server.com",
        ),
        verifiers=[
            JWTVerifier(
                jwks_uri="https://internal-issuer.example.com/.well-known/jwks.json",
                issuer="https://internal-issuer.example.com",
                audience="my-mcp-server",
            ),
        ],
    )

    mcp = FastMCP("My Server", auth=auth)

Interactive MCP clients authenticate through the OAuth proxy as usual. Backend services skip OAuth entirely and send a JWT signed by the internal issuer. Both paths are validated, and the first match wins.

##
​
Verification Order

`MultiAuth` checks sources in a deterministic order:

1. Server (if provided) — the full auth provider’s `verify_token` runs first
2. Verifiers — each `TokenVerifier` is tried in list order

The first source that returns a valid `AccessToken` wins. If every source returns `None`, the request receives a 401 response. This ordering means the server acts as the “primary” authentication path, with verifiers as fallbacks for tokens the server doesn’t recognize.

##
​
Verifiers Only

You don’t always need a full OAuth server. If your server only needs to accept tokens from multiple issuers, pass verifiers without a server:

    from fastmcp import FastMCP
    from fastmcp.server.auth import MultiAuth
    from fastmcp.server.auth.providers.jwt import JWTVerifier, StaticTokenVerifier

    auth = MultiAuth(
        verifiers=[
            JWTVerifier(
                jwks_uri="https://issuer-a.example.com/.well-known/jwks.json",
                issuer="https://issuer-a.example.com",
                audience="my-server",
            ),
            JWTVerifier(
                jwks_uri="https://issuer-b.example.com/.well-known/jwks.json",
                issuer="https://issuer-b.example.com",
                audience="my-server",
            ),
        ],
    )

    mcp = FastMCP("Multi-Issuer Server", auth=auth)

Without a server, no OAuth routes or metadata are served. This is appropriate for internal systems where clients already know how to obtain tokens.

##
​
API Reference

###
​
MultiAuth

Parameter | Type | Description
--- | --- | ---
`server` | `AuthProvider | None` | Optional auth provider that owns routes and OAuth metadata. Also tried first for token verification.
`verifiers` | `list[TokenVerifier] | TokenVerifier` | One or more token verifiers tried after the server.
`base_url` | `str | None` | Override the base URL. Defaults to the server’s `base_url`.
`required_scopes` | `list[str] | None` | Override required scopes. Defaults to the server’s scopes.

Full OAuth Server
Previous
Authorization
Next
Ctrl+I
Assistant
Responses are generated using AI and may contain mistakes.
\n\n
\n
\n \n
\n
","contacts":" \n
\n\n Prefab\n \n \n \n \n\n
\n
\n \n
\n
","dashboard":" \n
\n\n Prefab\n \n \n \n \n\n
\n
\n \n
\n
","data-table":" \n
\n\n Prefab\n \n \n \n \n\n
\n
\n \n
\n
","hitchhikers":" \n
\n\n Prefab Showcase\n \n \n \n \n\n
\n
\n \n
\n
","pie-chart":" \n
\n\n Prefab\n \n \n \n \n\n
\n
\n \n
\n
","reactive":" \n
\n\n Prefab\n \n \n \n \n\n
\n
\n \n
\n
","team-directory-reactive":" \n
\n\n Prefab\n \n \n \n \n\n
\n
\n \n
\n
","team-directory":" \n
\n\n Prefab\n \n \n \n \n\n
\n
\n \n
\n
"};