Configure Bearer auth in MCP server
With the latest MCP specification, your MCP server acts as a Resource Server that validates access tokens for protected resources. MCP Auth provides various ways to configure Bearer authorization:
- JWT (JSON Web Token) mode: A built-in authorization method that verifies JWTs with claim assertions.
- Custom mode: Allows you to implement your own authorization logic.
The Bearer auth middleware now requires specifying which resource the endpoint belongs to, enabling proper token validation against the configured authorization servers.
Configure Bearer auth with JWT mode
If your OAuth / OIDC provider issues JWTs for authorization, you can use the built-in JWT mode in MCP Auth. It verifies the JWT signature, expiration, and other claims you specify; then it populates the authentication information in the request context for further processing in your MCP implementation.
Scope validation
Here's an example of the basic scope validation:
- Python
- Node.js
from mcpauth import MCPAuth
from starlette.applications import Starlette
from starlette.middleware import Middleware
from starlette.routing import Mount
from mcp.server.fastmcp import FastMCP
mcp = FastMCP("MyMCPServer")
mcp_auth = MCPAuth(
# Initialize with your auth server config
)
bearer_auth = mcp_auth.bearer_auth_middleware("jwt",
resource="https://api.example.com", # Specify which resource this endpoint belongs to
audience="https://api.example.com", # Enable audience validation for security
required_scopes=["read", "write"]
)
app = Starlette(
routes=[Mount('/', app=mcp.sse_app(), middleware=[Middleware(bearer_auth)])]
)
import express from 'express';
import { MCPAuth } from 'mcp-auth';
const app = express();
const mcpAuth = new MCPAuth({
/* ... */
});
const bearerAuth = mcpAuth.bearerAuth('jwt', {
resource: 'https://api.example.com', // Specify which resource this endpoint belongs to
audience: 'https://api.example.com', // Enable audience validation for security
requiredScopes: ['read', 'write']
});
app.use('/mcp', bearerAuth, (req, res) => {
// Now `req.auth` contains the auth info
console.log(req.auth);
});
In the example above, we specified that the JWT requires the read
and write
scopes. If the JWT does not contain any of these scopes, the request will be rejected with a 403 Forbidden error.
Audience validation (RFC 8707)
For secure token validation, you should always include audience validation by specifying the audience
parameter. This validates the aud
(audience) claim in the JWT to ensure that the token was specifically issued for your MCP server resource.
The audience
parameter is required by the OAuth 2.0 specification for secure token validation. However, it is currently optional to maintain compatibility with authorization servers that do not yet support resource identifiers. For security reasons, please always include the audience parameter when possible. Future versions will enforce audience validation as mandatory to fully comply with the specification.
The audience value should typically match your resource identifier:
- Python
- Node.js
bearer_auth = mcp_auth.bearer_auth_middleware(
"jwt",
resource="https://api.example.com", # Specify which resource this endpoint belongs to
audience="https://api.example.com", # Enable audience validation for security
required_scopes=["read", "write"]
)
const bearerAuth = mcpAuth.bearerAuth('jwt', {
resource: 'https://api.example.com', // Specify which resource this endpoint belongs to
audience: 'https://api.example.com', // Enable audience validation for security
requiredScopes: ['read', 'write'],
});
In the example above, MCP Auth will validate both the aud
claim in the JWT and the required scopes.
Provide custom options to the JWT verification
You can also provide custom options to the underlying JWT verification library:
- Python
- Node.js
In Python SDK, we use PyJWT for JWT verification. You can the following options:
leeway
: Allow a certain amount of leeway when verifying the JWT expiration time (in seconds). Default is 60 seconds.
bearer_auth = mcp_auth.bearer_auth_middleware(
"jwt",
resource="https://api.example.com",
audience="https://api.example.com",
required_scopes=["read", "write"],
leeway=10, # Reduce clock skew by allowing 10 seconds leeway
)
In Node.js SDK, we use jose library for JWT verification. You can provide the following options:
jwtVerify
: Options for the JWT verification process (jwtVerify
function fromjose
).remoteJwtSet
: Options for fetching the remote JWT set (createRemoteJWKSet
function fromjose
).
const bearerAuth = mcpAuth.bearerAuth('jwt', {
resource: 'https://api.example.com',
audience: 'https://api.example.com',
requiredScopes: ['read', 'write'],
jwtVerify: {
clockTolerance: 60, // Allow a 60 seconds clock skew
},
remoteJwtSet: {
timeoutDuration: 10 * 1000, // 10 seconds timeout for remote JWT set fetching
},
});
Configure Bearer auth with custom verification
If your OAuth / OIDC provider does not issue JWTs, or you want to implement your own authorization logic, MCP Auth allows you to create a custom verification function:
Since the Bearer auth middleware will check against issuer (iss
), audience (aud
), and required scopes (scope
) with the given verification result, there's no need to implement these checks in your custom verification function. You can focus on verifying the token validity (e.g., signature, expiration, etc.) and returning the auth info object.
- Python
- Node.js
from mcpauth.exceptions import MCPAuthJwtVerificationException, MCPAuthJwtVerificationExceptionCode
from mcpauth.types import AuthInfo
async def custom_verification(token: str) -> AuthInfo:
# Implement your custom verification logic here
info = await verify_token(token)
if not info:
raise MCPAuthJwtVerificationException(
MCPAuthJwtVerificationExceptionCode.JWT_VERIFICATION_FAILED
)
return info # Return the auth info object
bearer_auth = mcp_auth.bearer_auth_middleware(
custom_verification,
resource="https://api.example.com",
audience="https://api.example.com", # Enable audience validation for security
required_scopes=["read", "write"]
)
const bearerAuth = mcpAuth.bearerAuth(
async (token) => {
// Implement your custom verification logic here
const info = await verifyToken(token);
if (!info) {
throw new MCPAuthJwtVerificationError('jwt_verification_failed');
}
return info; // Return the auth info object
},
{
resource: 'https://api.example.com',
audience: 'https://api.example.com', // Enable audience validation for security
requiredScopes: ['read', 'write']
}
);
Apply Bearer auth in your MCP server
To protect your MCP server with Bearer auth, you need to apply the Bearer auth middleware to your MCP server instance.
- Python
- Node.js
bearer_auth = mcp_auth.bearer_auth_middleware("jwt",
resource="https://api.example.com",
audience="https://api.example.com", # Enable audience validation for security
required_scopes=["read", "write"]
)
app = Starlette(
routes=[Mount('/', app=mcp.sse_app(), middleware=[Middleware(bearer_auth)])]
)
const app = express();
app.use(mcpAuth.bearerAuth('jwt', {
resource: 'https://api.example.com',
audience: 'https://api.example.com', // Enable audience validation for security
requiredScopes: ['read', 'write']
}));
This will ensure that all incoming requests are authenticated and authorized according to the configured Bearer auth settings, and the auth information will be available in the request context.
You can then access the information in your MCP server implementation:
- Python
- Node.js
@mcp.tool()
async def whoami() -> dict:
# `mcp_auth.auth_info` is the context object for the current request
auth_info = mcp_auth.auth_info
print(f"Authenticated user: {auth_info.subject}")
return {"subject": auth_info.subject}
// `authInfo` will be carried from the `req.auth` object
server.tool('whoami', ({ authInfo }) => {
console.log(`Authenticated user: ${authInfo.subject}`);
return { subject: authInfo.subject };
});