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.
Verification Order
MultiAuth checks sources in a deterministic order:
- Server (if provided) — the full auth provider’s
verify_tokenruns first - Verifiers — each
TokenVerifieris tried in mapping or list order
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:Challenge Scopes
Clients use theWWW-Authenticate challenge to decide which scopes to request. When you omit required_scopes or pass None, MultiAuth delegates default challenge selection to its server, or to its sole verifier when no server is configured. This preserves custom get_challenge_scopes(None) hooks. With multiple verifiers and no server, it does not select or combine their defaults; no scope parameter is advertised unless you configure required_scopes.
An explicit required_scopes list is passed to the delegated challenge hook and also sets the scopes required by MultiAuth’s HTTP middleware. An empty list removes that outer scope requirement. Each verifier still enforces its own token validation requirements, so required_scopes=[] does not make invalid or under-scoped tokens valid.
When the server is a RemoteAuthProvider, its configured challenge_scopes applies when the effective scopes equal that provider’s required_scopes, including an explicit list with the same values. A different explicit list is passed to the verifier’s hook for translation. Without configured challenge_scopes, the verifier receives the supplied list, or None to select its default.
Source Names
Each source has a stable identity for sessions, background tasks, and continued requests. Use an ordered mapping to give verifiers explicit names; passserver_source_id to name the delegated auth server. These names follow the source across restarts and changes to verification order. MultiAuth qualifies the returned token’s client_id with this source identity and the verified issuer and subject, when present. Its original_client_id field contains the identifier returned by the verifier; bearer token bytes, claims, subject, and scopes stay the same.
This changes
get_access_token().client_id and ownership for existing MultiAuth sessions, tasks, and continued requests. Update authorization checks that compare the verifier’s original client ID to read get_access_token().original_client_id instead. Recreate sessions and resubmit tasks after upgrading. Configurations with duplicate derived identities now need explicit names, including multiple static verifiers or custom verifiers of the same type. Changing a source name starts a new ownership scope.
