AI Workflows

Implement MCP Authentication Using OAuth 2.1

Learn how to add MCP authentication using OAuth 2.1, following a step-by-step guide for secure remote server access.

4 min read

Learn how to set up MCP authentication using OAuth 2.1. This step-by-step guide walks you through the process to securely authorize remote MCP servers. We'll use the ScaleKit service to simplify the implementation, ensuring that your server complies with the OAuth 2.1 standard effectively.

Prerequisites

Before proceeding, ensure you have the following:

prerequisites

  • An MCP server configured using FastAPI.
  • Installed Python libraries, including the scalekit package.
  • Access to a ScaleKit account for managing authentication workflows.
  • Basic knowledge of OAuth 2.1 and its principles.
  • Pre-configured environment variables:
    • SCALEKIT_CLIENT_ID
    • SCALEKIT_CLIENT_SECRET
    • SCALEKIT_ENVIRONMENT_URL
    • RESOURCE_METADATA_URL (for your MCP server).

Setting Up ScaleKit Authentication

Configure your ScaleKit account to manage MCP authentication.

steps

  1. Create an account or sign in at ScaleKit.
  2. Activate full-stack authentication in the ScaleKit environment.
  3. Add necessary scopes, such as:
    • Name: search:read
    • Description: "Use Tavili to search the web."
  4. Register your MCP server using its identifier URL.
    • Make sure the URL includes a trailing slash, e.g., http://localhost:10000/mcp/.
  5. Generate the client ID, client secret, and other credentials from ScaleKit and store them securely.

Creating the Well-Known Endpoint

Add a discovery endpoint to your MCP server for authentication workflows.

steps

  1. Add the following @app.get route to your FastAPI application for the well-known endpoint:
    python
    from fastapi import FastAPI
    import os
    import json
    
    app = FastAPI()
    
    @app.get("/.well-known/oauth-protected-resource/mcp")
    async def well_known_endpoint():
        metadata = os.getenv("METADATA_JSON", '{"issuer":"https://example.com","authorization_endpoint":"/oauth/authorize","token_endpoint":"/oauth/token"}')
        return json.loads(metadata)
  2. Ensure the endpoint is accessible publicly (without authentication).
  3. Test the endpoint manually using cURL:
    bash
    curl http://localhost:10000/.well-known/oauth-protected-resource/mcp
    # Expected output (example):
    # {
    #   "issuer": "https://example.com",
    #   "authorization_endpoint": "/oauth/authorize",
    #   "token_endpoint": "/oauth/token"
    # }

Adding Authentication Middleware

Add middleware to your MCP server to validate requests and enforce authorization.

steps

  1. Install the ScaleKit Python SDK:
    bash
    pip install scalekit
  2. Implement authentication middleware:
    python
    from starlette.middleware.base import BaseHTTPMiddleware
    from starlette.exceptions import HTTPException
    from scalekit.client import ScaleKit
    from scalekit.models import TokenValidationOptions
    import os
    
    class AuthMiddleware(BaseHTTPMiddleware):
        def __init__(self, app):
            super().__init__(app)
            self.scalekit = ScaleKit(
                environment_url=os.getenv("SCALEKIT_ENVIRONMENT_URL"),
                client_id=os.getenv("SCALEKIT_CLIENT_ID"),
                client_secret=os.getenv("SCALEKIT_CLIENT_SECRET")
            )
        
        async def dispatch(self, request, call_next):
            # Skip validation for well-known endpoints
            if request.url.path.startswith("/.well-known"):
                return await call_next(request)
    
            # Check for Bearer token
            auth_header = request.headers.get("Authorization")
            if not auth_header or not auth_header.startswith("Bearer "):
                raise HTTPException(status_code=401, headers={
                    "WWW-Authenticate": f'Bearer realm="OAuth", resource="{os.getenv("RESOURCE_METADATA_URL")}"',
                })
    
            token = auth_header.split(" ")[1]
            options = TokenValidationOptions(
                issuer=os.getenv("SCALEKIT_ENVIRONMENT_URL"),
                audience=os.getenv("RESOURCE_METADATA_NAME")
            )
    
            try:
                self.scalekit.validate_token(token, options)
            except Exception as e:
                raise HTTPException(status_code=401, detail=str(e))
    
            return await call_next(request)
    
    app.add_middleware(AuthMiddleware)
  3. Restart your MCP server to apply changes.
    bash
    uvicorn app:app --reload --host 0.0.0.0 --port 10000
  4. Test unauthorized requests to validate the 401 response:
    bash
    curl -i http://localhost:10000/mcp
    # HTTP/1.1 401 Unauthorized
    # WWW-Authenticate: Bearer realm="OAuth", resource="http://localhost:10000/.well-known/oauth-protected-resource/mcp"

Testing the Authentication Workflow

Verify the full authentication and authorization flow to ensure proper functionality.

steps

  1. Restart your MCP server with updated configurations:
    bash
    uvicorn app:app --reload
  2. Perform an unauthorized request:
    bash
    curl -i http://localhost:10000/mcp
    # Confirm a 401 error with proper headers (e.g., WWW-Authenticate).
  3. Authenticate with ScaleKit and obtain a valid token.
  4. Retry the request with the token:
    bash
    curl -i -H "Authorization: Bearer <valid-token>" http://localhost:10000/mcp/tools
    # Expected output:
    # List of tools with scopes and capabilities
  5. Use an MCP client to interact with server tools after successful token authentication.


FAQ

What is MCP OAuth 2.1?

MCP OAuth 2.1 is the authorization standard required for remotely accessing and securing Modern Compute Protocol (MCP) servers. It uses the OAuth 2.1 framework to ensure secure client authentication and token-based authorization.

Do I need to write my own authorization server?

No, you can avoid maintaining a custom authorization server by using third-party services like ScaleKit, which handle the complex aspects of OAuth 2.1 and streamline the authentication setup.

Can I use this guide for non-FastAPI MCP servers?

Yes, the steps demonstrated here are generalizable to different server frameworks. However, the implementation details of middleware might differ depending on the framework used.


Official reference: Model Context Protocol documentation.