Authentication¶
Authentication for the MCP endpoint is a Litestar middleware concern.
Apps that already have an authentication middleware (JWT backends,
Google IAP, custom token validators) get MCP authentication for free —
the middleware populates request.user and request.auth before
any route handler runs, including MCP tool handlers.
Authentication only establishes caller identity. See Security for object-level authorization patterns, transport identity boundaries, and safe file/path argument guidance.
MCPAuthConfig is metadata-only: it
describes the auth surface advertised by
/.well-known/oauth-protected-resource so MCP clients can discover
how to obtain a token. Enforcement lives in whichever middleware you
install on the app.
Three Integration Paths¶
Path A — Bring your own auth middleware.
Use this when your Litestar app already ships an
AbstractAuthenticationMiddleware
(or Litestar's built-in JWT backends). MCP tool handlers inherit
request.user / request.auth automatically. No MCPAuthBackend
needed. See docs/examples/notes/sqlspec/google_iap.py.
Path B — Built-in MCPAuthBackend.
Install
MCPAuthBackend via DefineMiddleware.
It validates bearer tokens against OIDC providers and/or a custom
token_validator, then populates connection.user via an optional
user_resolver. See docs/examples/notes/sqlspec/cloud_run_jwt.py.
MCPAuthBackend with a custom validator¶app = Litestar(
route_handlers=[],
plugins=[LitestarMCP(MCPConfig(auth=MCPAuthConfig(issuer="https://auth.example.com")))],
middleware=[DefineMiddleware(MCPAuthBackend, token_validator=validate_token)],
)
Path C — MCPAuthBackend with OIDC providers.
For production OIDC workloads, pass one or more
OIDCProviderConfig entries. The backend
handles JWKS discovery, caching, and signature verification.
MCPAuthBackend with OIDC auto-discovery¶app = Litestar(
route_handlers=[],
plugins=[
LitestarMCP(
MCPConfig(
auth=MCPAuthConfig(
issuer="https://auth.example.com",
audience="https://api.example.com/mcp",
)
)
)
],
middleware=[
DefineMiddleware(
MCPAuthBackend,
providers=[
OIDCProviderConfig(
issuer="https://auth.example.com",
audience="https://api.example.com/mcp",
algorithms=["RS256"],
)
],
)
],
)
Identity Proxies (custom header / prefix)¶
Cloud identity proxies verify the caller and inject a signed JWT into a
non-standard header. Google Cloud IAP uses X-Goog-IAP-JWT-Assertion
with the raw token (no Bearer prefix). Point the built-in validation
engine at that header with header_name / token_prefix instead of
writing a bespoke middleware — caching and user_resolver are unchanged.
IAP signs with ES256 and publishes a fixed JWK set (there is no OIDC
discovery document), so set jwks_uri and algorithms explicitly:
from litestar.middleware import DefineMiddleware
from litestar_mcp import MCPAuthBackend, OIDCProviderConfig
DefineMiddleware(
MCPAuthBackend,
providers=[
OIDCProviderConfig(
issuer="https://cloud.google.com/iap",
audience="/projects/PROJECT_NUMBER/apps/PROJECT_ID",
jwks_uri="https://www.gstatic.com/iap/verify/public_key-jwk",
algorithms=["ES256"],
),
],
header_name="X-Goog-IAP-JWT-Assertion",
token_prefix="",
)
header_name lookup is case-insensitive. When token_prefix is empty,
the entire header value is the token, and an absent header is reported as a
missing-header error (401 with WWW-Authenticate) rather than an
invalid-token error. The defaults (Authorization header with the
Bearer prefix) preserve standard bearer behaviour, so existing deployments
need no changes.
The same header_name / token_prefix extraction applies to any proxy
that forwards a token in a custom header (e.g. AWS ALB's X-Amzn-Oidc-Data).
Providers whose keys are not published as a JWK set — ALB signs with
per-region PEM keys rather than a JWKS document — need a custom
token_validator for the validation step rather than OIDCProviderConfig.
Composable OIDC Factory¶
create_oidc_validator() returns an async
callable that validates a single token against an OIDC issuer. Pass it
as MCPAuthBackend(token_validator=...) or use it inside your own
middleware. Both clock_skew and jwks_cache_ttl are configurable.
Injectable JWKS Cache¶
JWKSCache is a protocol-shaped seam for
apps that already run their own JWKS / OIDC discovery cache. Pass a
shared instance to every validator to avoid redundant network fetches:
docs/examples/snippets/jwks_cache_shared.py¶from litestar_mcp import DefaultJWKSCache, create_oidc_validator
from litestar_mcp.auth import OIDCProviderConfig
shared_cache = DefaultJWKSCache()
validator_a = create_oidc_validator(
"https://company.okta.com",
"api://mcp-tools",
jwks_cache=shared_cache,
)
provider_b = OIDCProviderConfig(
issuer="https://company.okta.com",
audience="api://admin",
jwks_cache=shared_cache,
)
When no cache is passed, the validator uses a process-wide default —
matching 0.4.0 behaviour — so existing apps need no code changes. Any
object implementing async get / async set(*, ttl=int) /
async invalidate satisfies the protocol, so a Redis-backed or
application-specific cache can drop in cleanly.
Discovery Metadata¶
When MCPAuthConfig is attached to
MCPConfig, the plugin publishes
/.well-known/oauth-protected-resource with the configured
issuer, audience, and scopes. This endpoint is always
unauthenticated (via Litestar's exclude_from_auth opt key) so
clients can bootstrap their auth flow.
Mapping Claims to Users¶
Middleware populates request.auth with the validated claims dict
and request.user with the resolved user object (if a
user_resolver is configured). Tool handlers access these via
normal Litestar DI:
Read
request.userdirectly in the handler signature.Write a
Provide(...)dependency that extracts the identity fromrequest.userand returns a domain type.Enforce scopes or roles via guards that inspect
request.auth.
See the reference-notes examples for end-to-end wiring across JWT, Dishka, Advanced Alchemy, and Google IAP variants.