Authorization
When building a Model Context Protocol (MCP) ↗ server, you need both a way to allow users to login (authentication) and allow them to grant the MCP client access to resources on their account (authorization).
The Model Context Protocol uses a subset of OAuth 2.1 for authorization ↗. OAuth allows your users to grant limited access to resources, without them having to share API keys or other credentials.
Cloudflare provides an OAuth Provider Library ↗ that implements the provider side of the OAuth 2.1 protocol, allowing you to easily add authorization to your MCP server.
You can use the OAuth Provider Library in three ways:
- Your Worker handles authorization itself. Your MCP server, running on Cloudflare, handles the complete OAuth flow. (Example)
- Integrate directly with a third-party OAuth provider, such as GitHub or Google.
- Integrate with your own OAuth provider, including authorization-as-a-service providers you might already rely on, such as Stytch, Auth0, or WorkOS.
The following sections describe each of these options and link to runnable code examples for each.
Your MCP Server, using the OAuth Provider Library ↗, can handle the complete OAuth authorization flow, without any third-party involvement.
The Workers OAuth Provider Library ↗ is a Cloudflare Worker that implements a fetch()
handler, and handles incoming requests to your MCP server.
You provide your own handlers for your MCP Server's API, and autentication and authorization logic, and URI paths for the OAuth endpoints, as shown below:
export default new OAuthProvider({ apiRoute: "/mcp", // Your MCP server: apiHandler: MyMCPServer.Router, // Your handler for authentication and authorization: defaultHandler: MyAuthHandler, authorizeEndpoint: "/authorize", tokenEndpoint: "/token", clientRegistrationEndpoint: "/register",});
Refer to the getting started example for a complete example of the OAuthProvider
in use, with a mock authentication flow.
The authorization flow in this case works like this:
sequenceDiagram participant B as User-Agent (Browser) participant C as MCP Client participant M as MCP Server (your Worker) C->>M: MCP Request M->>C: HTTP 401 Unauthorized Note over C: Generate code_verifier and code_challenge C->>B: Open browser with authorization URL + code_challenge B->>M: GET /authorize Note over M: User logs in and authorizes M->>B: Redirect to callback URL with auth code B->>C: Callback with authorization code C->>M: Token Request with code + code_verifier M->>C: Access Token (+ Refresh Token) C->>M: MCP Request with Access Token Note over C,M: Begin standard MCP message exchange
Remember — authentication is different from authorization ↗. Your MCP Server can handle authorization itself, while still relying on an external authentication service to first authenticate users. The example in getting started provides a mock authentication flow. You will need to implement your own authentication handler — either handling authentication yourself, or using an external authentication services.
The OAuth Provider Library ↗ can be configured to use a third-party OAuth provider, such as GitHub or Google. You can see a complete example of this in the GitHub example.
When you use a third-party OAuth provider, you must provide a handler to the OAuthProvider
that implements the OAuth flow for the third-party provider.
import MyAuthHandler from "./auth-handler";
export default new OAuthProvider({ apiRoute: "/mcp", // Your MCP server: apiHandler: MyMCPServer.Router, // Replace this handler with your own handler for authentication and authorization with the third-party provider: defaultHandler: MyAuthHandler, authorizeEndpoint: "/authorize", tokenEndpoint: "/token", clientRegistrationEndpoint: "/register",});
Note that as defined in the Model Context Protocol specification ↗ when you use a third-party OAuth provider, the MCP Server (your Worker) generates and issues its own token to the MCP client:
sequenceDiagram participant B as User-Agent (Browser) participant C as MCP Client participant M as MCP Server (your Worker) participant T as Third-Party Auth Server C->>M: Initial OAuth Request M->>B: Redirect to Third-Party /authorize B->>T: Authorization Request Note over T: User authorizes T->>B: Redirect to MCP Server callback B->>M: Authorization code M->>T: Exchange code for token T->>M: Third-party access token Note over M: Generate bound MCP token M->>B: Redirect to MCP Client callback B->>C: MCP authorization code C->>M: Exchange code for token M->>C: MCP access token
Read the docs for the Workers oAuth Provider Library ↗ for more details.
If your application already implements an Oauth Provider itself, or you use Stytch ↗, Auth0 ↗, WorkOS ↗, or authorization-as-a-service provider, you can use this in the same way that you would use a third-party OAuth provider, described above in (2).
You can use the auth provider to:
- Allow users to authenticate to your MCP server through email, social logins, SSO (single sign-on), and MFA (multi-factor authentication).
- Define scopes and permissions that directly map to your MCP tools.
- Present users with a consent page corresponding with the requested permissions.
- Enforce the permissions so that agents can only invoke permitted tools.
Get started with a remote MCP server that uses Stytch ↗ to allow users to sign in with email, Google login or enterprise SSO and authorize their AI agent to view and manage their company’s OKRs on their behalf. Stytch will handle restricting the scopes granted to the AI agent based on the user’s role and permissions within their organization. When authorizing the MCP Client, each user will see a consent page that outlines the permissions that the agent is requesting that they are able to grant based on their role.
For more consumer use cases, deploy a remote MCP server for a To Do app that uses Stytch for authentication and MCP client authorization. Users can sign in with email and immediately access the To Do lists associated with their account, and grant access to any AI assistant to help them manage their tasks.
Get started with a remote MCP server that uses Auth0 to authenticate users through email, social logins, or enterprise SSO to interact with their todos and personal data through AI agents. The MCP server securely connects to API endpoints on behalf of users, showing exactly which resources the agent will be able to access once it gets consent from the user. In this implementation, access tokens are automatically refreshed during long running interactions.
To set it up, first deploy the protected API endpoint:
Then, deploy the MCP server that handles authentication through Auth0 and securely connects AI agents to your API endpoint.
Get started with a remote MCP server that uses WorkOS's AuthKit to authenticate users and manage the permissions granted to AI agents. In this example, the MCP server dynamically exposes tools based on the user's role and access rights. All authenticated users get access to the add
tool, but only users who have been assigned the image_generation
permission in WorkOS can grant the AI agent access to the image generation tool. This showcases how MCP servers can conditionally expose capabilities to AI agents based on the authenticated user's role and permission.
When a user authenticates to your MCP server through Cloudflare's OAuth Provider, their identity information and tokens are made available through the props
parameter.
export class MyMCP extends McpAgent<Env, unknown, AuthContext> { async init() { this.server.tool("userInfo", "Get user information", {}, async () => ({ content: [{ type: "text", text: `Hello, ${this.props.claims.name || "user"}!` }], })); }}
The authentication context can be used for:
- Accessing user-specific data by using the user ID (this.props.claims.sub) as a key
- Checking user permissions before performing operations
- Customizing responses based on user preferences or attributes
- Using authentication tokens to make requests to external services on behalf of the user
- Ensuring consistency when users interact with your application through different interfaces (dashboard, API, MCP server)
You can implement fine-grained authorization controls for your MCP tools based on user permissions. This allows you to restrict access to certain tools based on the user's role or specific permissions.
// Create a wrapper function to check permissionsfunction requirePermission(permission, handler) { return async (request, context) => { // Check if user has the required permission const userPermissions = context.props.permissions || [];
if (!userPermissions.includes(permission)) { return { content: [{ type: "text", text: `Permission denied: requires ${permission}` }], status: 403 }; }
// If permission check passes, execute the handler return handler(request, context); };}
// Use the wrapper with your MCP toolsasync init() { // Basic tools available to all authenticated users this.server.tool("basicTool", "Available to all users", {}, async () => { // Implementation for all users });
// Protected tool using the permission wrapper this.server.tool( "adminAction", "Administrative action requiring special permission", { /* parameters */ }, requirePermission("admin", async (req) => { // Only executes if user has "admin" permission return { content: [{ type: "text", text: "Admin action completed" }] }; }) );
// Conditionally register tools based on user permissions if (this.props.permissions?.includes("special_feature")) { this.server.tool("specialTool", "Special feature", {}, async () => { // This tool only appears for users with the special_feature permission }); }}
Benefits:
- Authorization check at the tool level ensures proper access control
- Allows you to define permission checks once and reuse them across tools
- Provides clear feedback to users when permission is denied
- Can choose to only present tools that the agent is able to call
- Learn how to use the Workers OAuth Provider Library ↗
- Learn how to use a third-party OAuth provider, using the GitHub example MCP server.
Was this helpful?
- Resources
- API
- New to Cloudflare?
- Products
- Sponsorships
- Open Source
- Support
- Help Center
- System Status
- Compliance
- GDPR
- Company
- cloudflare.com
- Our team
- Careers
- 2025 Cloudflare, Inc.
- Privacy Policy
- Terms of Use
- Report Security Issues
- Trademark