Configure Bearer auth in MCP server
MCP Auth provides various ways to configure Bearer authorization in your MCP server:
- 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.
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", 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', { 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.
Resource indicator validation (RFC 8707)
If your provider is based on OIDC, or supports the Resource Indicator extension, you may also specify the audience
option to validate the aud
(audience) claim in the JWT. This is useful to ensure that the JWT is intended for your MCP server.
Check your provider's documentation to see if it supports the Resource Indicator extension and how to configure it. Some providers may use other terms like "audience", "API resource", or "API indicator" to refer to the same concept.
Once the resource indicator is configured, you can specify it in the bearerAuth
middleware:
- Python
- Node.js
bearer_auth = mcp_auth.bearer_auth_middleware(
"jwt",
audience="https://api.example.com/mcp", # The expected audience for the JWT
required_scopes=["read", "write"]
)
const bearerAuth = mcpAuth.bearerAuth('jwt', {
audience: 'https://api.example.com/mcp', // The expected audience for the JWT
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",
audience="https://api.example.com/mcp",
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', {
audience: 'https://api.example.com/mcp',
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,
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
},
{ 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", required_scopes=["read", "write"])
app = Starlette(
routes=[Mount('/', app=mcp.sse_app(), middleware=[Middleware(bearer_auth)])]
)
const app = express();
app.use(mcpAuth.bearerAuth('jwt', { 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 };
});