fastmcp/docs/servers/auth/verifiers.mdx

332 lines
10 KiB
Text

---
title: Token Verification
sidebarTitle: Token Verification
description: Secure your FastMCP server's HTTP endpoints by validating JWT tokens.
icon: key
tag: NEW
---
import { VersionBadge } from "/snippets/version-badge.mdx"
<VersionBadge version="2.11.0" />
<Tip>
Authentication and authorization are only relevant for HTTP-based transports.
</Tip>
Bearer Token authentication is a common way to secure HTTP-based APIs. In this model, the client sends a token (usually a JSON Web Token or JWT) in the `Authorization` header with the "Bearer" scheme. The server then validates this token to grant or deny access.
FastMCP supports Bearer Token authentication for its HTTP-based transports (`http` and `sse`), allowing you to protect your server from unauthorized access.
## Authentication Strategy
FastMCP uses **asymmetric encryption** for token validation, which provides a clean security separation between token issuers and FastMCP servers. This approach means:
- **No shared secrets**: Your FastMCP server never needs access to private keys or client secrets
- **Public key verification**: The server only needs a public key (or JWKS endpoint) to verify token signatures
- **Secure token issuance**: Tokens are signed by an external service using a private key that never leaves the issuer
- **Scalable architecture**: Multiple FastMCP servers can validate tokens without coordinating secrets
This design allows you to integrate FastMCP servers into existing authentication infrastructures without compromising security boundaries.
## Token Verification Approaches
FastMCP provides three token verification approaches:
### JWTVerifier
Validates JWT tokens using public key cryptography. Use when you have JWT tokens issued by an external identity provider (Auth0, Okta, Keycloak, etc.) and want self-contained validation without network calls.
### IntrospectionTokenVerifier
Validates tokens by calling a remote OAuth 2.0 authorization server's introspection endpoint (RFC 7662). Use when your authorization server is separate from your FastMCP server, you're using opaque tokens, or you need real-time token revocation.
### StaticTokenVerifier
Validates tokens against a predefined dictionary. Use for development and testing only - never in production.
<Warning>
These verifiers validate tokens; they do **not** issue them (or implement any part of an OAuth flow). You'll need to generate tokens separately, either using FastMCP utilities or an external Identity Provider (IdP) or OAuth 2.1 Authorization Server.
</Warning>
### Configuration Parameters
<Tabs>
<Tab title="JWTVerifier">
<Card icon="code" title="JWTVerifier Configuration">
<ParamField body="public_key" type="str">
RSA public key in PEM format for static key validation. Required if `jwks_uri` is not provided
</ParamField>
<ParamField body="jwks_uri" type="str">
URL for JSON Web Key Set endpoint. Required if `public_key` is not provided
</ParamField>
<ParamField body="issuer" type="str | None">
Expected JWT `iss` claim value
</ParamField>
<ParamField body="algorithm" type="str | None">
Algorithm for decoding JWT token. Defaults to 'RS256'
</ParamField>
<ParamField body="audience" type="str | None">
Expected JWT `aud` claim value
</ParamField>
<ParamField body="required_scopes" type="list[str] | None">
Global scopes required for all requests
</ParamField>
</Card>
</Tab>
<Tab title="IntrospectionTokenVerifier">
<Card icon="code" title="IntrospectionTokenVerifier Configuration">
<ParamField body="introspection_endpoint" type="str">
OAuth 2.0 Token Introspection endpoint URL (RFC 7662)
</ParamField>
<ParamField body="client_id" type="str">
Resource server client ID for introspection authentication
</ParamField>
<ParamField body="client_secret" type="str">
Resource server client secret for introspection authentication
</ParamField>
<ParamField body="required_scopes" type="list[str] | None">
Global scopes required for all requests
</ParamField>
</Card>
</Tab>
<Tab title="StaticTokenVerifier">
<Card icon="code" title="StaticTokenVerifier Configuration">
<ParamField body="valid_tokens" type="dict[str, dict]">
Mapping of valid tokens to their claims. Each token maps to a dictionary containing token metadata like `sub`, `scope`, etc.
</ParamField>
<ParamField body="required_scopes" type="list[str] | None">
Global scopes required for all requests
</ParamField>
</Card>
</Tab>
</Tabs>
## JWT Verification
The `JWTVerifier` validates JWT tokens using public key cryptography. Use this when you have JWT tokens issued by an external identity provider and want self-contained validation without network calls.
```python
from fastmcp import FastMCP
from fastmcp.server.auth.verifiers import JWTVerifier
verifier = JWTVerifier(
jwks_uri="https://my-identity-provider.com/.well-known/jwks.json",
issuer="https://my-identity-provider.com/",
audience="my-mcp-server"
)
mcp = FastMCP(name="My MCP Server", auth=verifier)
```
### Public Key Configuration
#### Using a Static Public Key
If you have a public key in PEM format, you can provide it to the `JWTVerifier` as a string.
```python {12}
from fastmcp.server.auth.verifiers import JWTVerifier
import inspect
public_key_pem = inspect.cleandoc(
"""
-----BEGIN PUBLIC KEY-----
MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAy...
-----END PUBLIC KEY-----
"""
)
auth = JWTVerifier(public_key=public_key_pem)
```
#### Using JWKS URI
```python
verifier = JWTVerifier(
jwks_uri="https://idp.example.com/.well-known/jwks.json"
)
```
<Note>
JWKS is recommended for production as it supports automatic key rotation and multiple signing keys.
</Note>
## OAuth 2.0 Token Introspection
The `IntrospectionTokenVerifier` validates tokens by calling an OAuth 2.0 authorization server's introspection endpoint (RFC 7662). This is useful when your authorization server is separate from your FastMCP server, you're using opaque tokens, or you need real-time token validation with immediate revocation support.
```python
from fastmcp.server.auth.verifiers import IntrospectionTokenVerifier
verifier = IntrospectionTokenVerifier(
introspection_endpoint="https://auth.company.com/oauth/introspect",
server_url="https://mcp.company.com", # This server's URL
client_id="mcp-resource-server",
client_secret="your-secret",
required_scopes=["mcp:access"]
)
mcp = FastMCP(name="MCP Server", auth=verifier)
```
For each request, the verifier makes an HTTP call to the introspection endpoint to check if the token is valid and active. This provides real-time validation but requires network connectivity.
## Static Token Verification
The `StaticTokenVerifier` validates tokens against a predefined dictionary of token strings and claims. Use this for development and testing when you need predictable tokens without setting up a real OAuth server.
```python
from fastmcp.server.auth.verifiers import StaticTokenVerifier
verifier = StaticTokenVerifier(
tokens={
"dev-token-123": {
"client_id": "dev-user",
"scopes": ["read", "write"],
"sub": "developer@example.com"
},
"readonly-token": {
"client_id": "readonly-user",
"scopes": ["read"],
"expires_at": 1735689600 # Optional expiration
}
},
required_scopes=["read"]
)
mcp = FastMCP(name="Development Server", auth=verifier)
```
Token claims can include `client_id` (required), `scopes`, `sub`, `expires_at`, and any custom metadata your application needs.
<Warning>
Never use StaticTokenVerifier in production - tokens are stored in plain text.
</Warning>
## Generating Tokens
For development and testing, FastMCP provides the `RSAKeyPair` utility class to generate tokens without needing an external OAuth provider.
<Warning>
The `RSAKeyPair` utility is intended for development and testing only. For production, use a proper OAuth 2.1 Authorization Server or Identity Provider.
</Warning>
### Basic Token Generation
```python
from fastmcp import FastMCP
from fastmcp.server.auth.verifiers import JWTVerifier, RSAKeyPair
# Generate a new key pair
key_pair = RSAKeyPair.generate()
# Configure the auth verifier with the public key
auth = JWTVerifier(
public_key=key_pair.public_key,
issuer="https://dev.example.com",
audience="my-dev-server"
)
mcp = FastMCP(name="Development Server", auth=auth)
# Generate a token for testing
token = key_pair.create_token(
subject="dev-user",
issuer="https://dev.example.com",
audience="my-dev-server",
scopes=["read", "write"]
)
print(f"Test token: {token}")
```
### Token Creation Parameters
The `create_token()` method accepts these parameters:
<Card icon="code" title="create_token() Parameters">
<ParamField body="subject" type="str" default="fastmcp-user">
JWT subject claim (usually user ID)
</ParamField>
<ParamField body="issuer" type="str" default="https://fastmcp.example.com">
JWT issuer claim
</ParamField>
<ParamField body="audience" type="str | None">
JWT audience claim
</ParamField>
<ParamField body="scopes" type="list[str] | None">
OAuth scopes to include
</ParamField>
<ParamField body="expires_in_seconds" type="int" default="3600">
Token expiration time in seconds
</ParamField>
<ParamField body="additional_claims" type="dict | None">
Extra claims to include in the token
</ParamField>
<ParamField body="kid" type="str | None">
Key ID for JWKS lookup
</ParamField>
</Card>
## Accessing Token Claims
Once authenticated, your tools, resources, or prompts can access token information using the `get_access_token()` dependency function:
```python
from fastmcp import FastMCP, Context, ToolError
from fastmcp.server.dependencies import get_access_token, AccessToken
@mcp.tool
async def get_my_data(ctx: Context) -> dict:
access_token: AccessToken = get_access_token()
user_id = access_token.client_id # From JWT 'sub' or 'client_id' claim
user_scopes = access_token.scopes
if "data:read_sensitive" not in user_scopes:
raise ToolError("Insufficient permissions: 'data:read_sensitive' scope required.")
return {
"user": user_id,
"sensitive_data": f"Private data for {user_id}",
"granted_scopes": user_scopes
}
```
### AccessToken Properties
<Card icon="code" title="AccessToken Properties">
<ParamField body="token" type="str">
The raw JWT string
</ParamField>
<ParamField body="client_id" type="str">
Authenticated principal identifier
</ParamField>
<ParamField body="scopes" type="list[str]">
Granted scopes
</ParamField>
<ParamField body="expires_at" type="datetime | None">
Token expiration timestamp
</ParamField>
</Card>