The Model Context Protocol (MCP) is revolutionizing how AI applications interact with external systems. But as your MCP server moves from prototype to production, one question becomes critical: How do you secure it with an auth and identity layer?
This guide walks you through implementing OAuth 2.1 authentication for your MCP server using Scalekit. We'll cover the complete implementation process, from initial setup to production deployment.
Implementation overview
Whether you’re building a brand new MCP server or retrofitting an existing one, OAuth implementation involves four steps.
Register your MCP Server and configure appropriate OAuth scopes
Let's walk through each step with practical code examples. You can also follow through with our video demo below.
1. Register your MCP server
Head over to the Scalekit dashboard to register your MCP server. Think of this step as provisioning your server’s identity and defining what permissions it can grant to clients.
Basic configuration
Server name: A user-friendly name (e.g., "Weather Assistant API")
Resource identifier: Your MCP server’s unique identifier, typically your server’s URL (e.g., https://api.weather-assistant.com)
Server logo: Upload a 45x45 pixel logo to help users recognize your service
Access control settings
Dynamic client registration: Enables MCP clients to register automatically
Offline access: Allow refresh tokens for long-term access
Token configuration:
Access tokens: 300-3600 seconds (5 minutes to 1 hour)
Refresh tokens: 300-86400 seconds (5 minutes to 24 hours)
Define scopes
Plan your scopes carefully so you can control which actions require which permissions. Examples:
mcp:tools:weather:read- Read weather data
mcp:tools:calendar:write - Modify calendar events
mcp:resources:customer-data:read - Access customer information
mcp:exec:workflows:* - Execute any workflow
2. Implement OAuth protected resource metadata
MCP clients discover your authorization server through the OAuth protected resource metadata endpoint. This is your server's "business card" for OAuth clients.
OAuth relies on metadata discovery so clients and tools can integrate without hard-coding endpoints. Your MCP server needs to expose an OAuth Protected Resource Metadata endpoint.
resource: Your MCP server's unique identifier (matches the aud claim in JWT tokens)
authorization_servers: List of trusted authorization servers
bearer_methods_supported: How tokens are transmitted (typically header)
scopes_supported: Available permissions for clients to request
You can find a complete reference format in the docs.
3. Implement JWT token validation
This is the heart of your security implementation. Every request to your MCP server should validate the incoming JWT token. Once your server is registered and metadata is available, every incoming request will include a Bearer token in the Authorization header.
Security best practices
Always validate the issuer - Ensure tokens come from your trusted authorization server
Check the audience - Verify tokens are intended for your server
import { jwtVerify, createRemoteJWKSet } from 'jose';
// Configure JWKS endpoint from your Scalekit instance
const JWKS = createRemoteJWKSet(
new URL('https://your-org.scalekit.com/.well-known/jwks')
);
// WWW-Authenticate header for 401 responses
const WWW_AUTHENTICATE_HEADER = [
'Bearer error="unauthorized"',
'error_description="Authorization required"',
`resource_metadata="https://your-mcp-server.com/.well-known/oauth-protected-resource"`
].join(', ');
const validateToken = async (req, res, next) => {
const authHeader = req.headers.authorization;
const token = authHeader?.match(/^Bearer (.+)$/)?.[1];
if (!token) {
return res
.set('WWW-Authenticate', WWW_AUTHENTICATE_HEADER)
.status(401)
.json({
error: 'unauthorized',
error_description: 'Bearer token required'
});
}
try {
const { payload } = await jwtVerify(token, JWKS, {
issuer: 'https://your-org.scalekit.com',
audience: 'https://your-mcp-server.com' // Your MCP server identifier
});
// Attach token claims to request for downstream use
req.auth = {
userId: payload.sub,
scopes: payload.scope?.split(' ') || [],
clientId: payload.client_id,
expiresAt: payload.exp
};
next();
} catch (error) {
console.error('Token validation failed:', error.message);
return res
.set('WWW-Authenticate', WWW_AUTHENTICATE_HEADER)
.status(401)
.json({
error: 'invalid_token',
error_description: 'Bearer token is invalid or expired'
});
}
};
// Apply to all MCP endpoints
app.use('/mcp', validateToken);
Feel free to adapt this pattern to your preferred language or framework.
4. Implement scope-based authorization
OAuth scopes enable fine-grained permission control. Validating the token’s signature proves the request is from an authenticated client, but you often also need to check if it has permission to perform a specific action. Here's how to implement scope checking:
Token caching: Cache JWKS Public Keys for 24 hours to reduce http calls and make token signature verification instantaneous
Connection pooling: Reuse HTTP connections for token validation
Async processing: Use async/await patterns for non-blocking operations
Error handling
// Comprehensive error handling
const handleAuthError = (error, req, res, next) => {
if (error.code === 'ERR_JWT_EXPIRED') {
return res.status(401).json({
error: 'token_expired',
error_description: 'The access token has expired'
});
}
if (error.code === 'ERR_JWT_INVALID') {
return res.status(401).json({
error: 'invalid_token',
error_description: 'The access token is malformed'
});
}
// Generic error response
return res.status(500).json({
error: 'server_error',
error_description: 'An internal server error occurred'
});
};
app.use(handleAuthError);
Conclusion
Implementing OAuth for your MCP server transforms it from a prototype into a production-ready service. The four-step process—registration, metadata implementation, token validation, and scope verification — provides a solid foundation for secure AI integrations.
With OAuth properly implemented, your MCP server can safely integrate with enterprise systems, handle sensitive data, and scale to meet production demands. The investment in proper authorization pays dividends in security, compliance, and user trust.
Ready to move forward? Consider Scalekit as drop-in OAuth authorization server for your MCP servers
If you want a deeper dive or ready-to-use code samples, explore our full guide here.