Skip to main content

Tutorial: OAuth2 Authentication for MCP Servers

Protect MCP endpoints with JWT validation by using Dapr bearer middleware.

This tutorial shows how to add OAuth2 authentication to an MCP server with Catalyst HTTP middleware pipelines. You will configure a bearer middleware that validates JWTs on every incoming request. Requests without a valid token are rejected before they reach your MCP server.

note

This tutorial uses Catalyst Cloud to get started quickly with zero infrastructure setup. Catalyst Cloud uses a tunnel to route service invocation requests from the cloud to your local development machine. For production or on-premises requirements, Diagrid also offers a self-hosted enterprise option where traffic stays within your private network.

You will learn how to:

  • Configure a Dapr HTTP bearer middleware component for JWT validation
  • Attach the middleware to an MCP server's HTTP pipeline
  • Verify that requests without a valid token are rejected
  • Configure the sample MCP client to automatically fetch and attach OAuth2 tokens

The bearer middleware intercepts incoming requests to the MCP server and validates the JWT by checking the issuer's JWKS (JSON Web Key Set), the iss (issuer) claim, and the aud (audience) claim. If the token is missing or invalid, the middleware returns a 401 Unauthorized before the request reaches application code.

1. Prerequisites

  • Completed the Access Policies tutorial, which uses the same project files (skip its final cleanup step so the mcp-access-qs project and App IDs remain in place)
  • An OAuth2 provider, such as Auth0, with:
    • A Machine-to-Machine application configured for the client credentials grant
    • An API audience defined

2. Set OAuth2 Credentials

export AUTH0_DOMAIN="your-tenant.us.auth0.com"
export AUTH0_CLIENT_ID="your-client-id"
export AUTH0_CLIENT_SECRET="your-client-secret"
export AUTH0_AUDIENCE="https://your-api-audience/"

3. Apply the Bearer Middleware Component

The catalyst-quickstart repo includes a bearer middleware component in resources/bearer-component.yaml. This component configures JWT validation against your OAuth2 provider and is scoped to the MCP server App ID only.

Apply it to Catalyst, substituting your environment variables:

envsubst < resources/bearer-component.yaml | diagrid apply -f -

4. Apply the OAuth Configuration

The tutorial also includes an app configuration in resources/mcp-server-oauth.yaml. This attaches the bearer middleware to the MCP server's HTTP pipeline, so every incoming request must include a valid JWT. Authorization is handled separately through access policies.

Apply the configuration and attach it to the MCP server App ID:

diagrid apply -f resources/mcp-server-oauth.yaml
diagrid appid update mcp-server \
--project mcp-access-qs \
--app-config mcp-server-oauth

The sample MCP client already includes OAuth2 support. When the AUTH0_* environment variables are set, it automatically fetches a token by using the client credentials grant and attaches it to requests. No code changes are required.

5. Test Without a Token

First, verify that the middleware rejects unauthenticated requests. Start the services without the AUTH0_* environment variables set, or unset them first:

unset AUTH0_DOMAIN AUTH0_CLIENT_ID AUTH0_CLIENT_SECRET AUTH0_AUDIENCE
diagrid dev run -f mcp-quickstart.yaml --project mcp-access-qs --approve

Trigger the MCP client:

curl -s -X POST http://localhost:5001/run | python -m json.tool

The request fails because the bearer middleware rejects it when no token is present.

6. Test With a Valid Token

Stop the services (Ctrl+C), then restart them with the OAuth2 environment variables set:

export AUTH0_DOMAIN="your-tenant.us.auth0.com"
export AUTH0_CLIENT_ID="your-client-id"
export AUTH0_CLIENT_SECRET="your-client-secret"
export AUTH0_AUDIENCE="https://your-api-audience/"
diagrid dev run -f mcp-quickstart.yaml --project mcp-access-qs --approve

Trigger the MCP client:

curl -s -X POST http://localhost:5001/run | python -m json.tool

The sample MCP client automatically fetches an OAuth2 token by using the client credentials grant and attaches it to the request. The bearer middleware validates the JWT, including the issuer and audience claims, and all MCP tools are invoked successfully:

{
"tools": [
{"name": "add", "description": "Add two numbers together."},
{"name": "get_weather_alert", "description": "Get a weather alert for a given city."},
{"name": "echo", "description": "Echo back a message."}
],
"add_result": "5",
"weather_alert": "Severe thunderstorm warning until 6 PM CDT",
"errors": []
}

7. Restore Default Configuration

To remove the OAuth middleware and return to the default configuration:

diagrid configuration create mcp-server-allow \
--project mcp-access-qs \
--default-action allow

diagrid appid update mcp-server \
--project mcp-access-qs \
--app-config mcp-server-allow

8. Clean Up

Stop the running application by pressing Ctrl+C.

Delete the Catalyst Cloud project:

diagrid project delete mcp-access-qs

Summary

In this tutorial, you:

  • Configured a Dapr HTTP bearer middleware component to validate JWTs against an OAuth2 provider
  • Attached the middleware to the MCP server's HTTP pipeline through a Catalyst configuration
  • Verified that unauthenticated requests are rejected before reaching the MCP server
  • Configured the sample MCP client to fetch and attach OAuth2 tokens automatically

Next Steps

  • Combine access policies and authentication for defense in depth: use access policies for authorization and bearer middleware for authentication
  • Learn more about Catalyst Enterprise for production deployments
  • Explore the Catalyst web console for managing configurations and components