DEV Community

Prashant Iyenga
Prashant Iyenga

Posted on • Originally published at Medium on

MCP Server Setup with OAuth Authentication using Auth0 and Claude.ai Remote MCP Integration

Introduction

This technical guide provides a comprehensive walkthrough for implementing a Model Context Protocol (MCP) server with robust OAuth 2.0 authentication, leveraging Auth0 as the identity provider. The focus is on achieving full compatibility with Claude.ai’s requirements for Dynamic Client Registration (DCR) as specified in RFC 7591. Unlike traditional OAuth integrations that rely on static client credentials, Claude.ai mandates that MCP servers support dynamic, standards-compliant registration and discovery endpoints, enabling third-party clients to obtain credentials and initiate secure authorization flows programmatically.

We will learn how to configure Auth0 to enable OIDC dynamic application registration, promote connections to domain-level for third-party authentication, and expose the necessary OAuth endpoints for automated client onboarding. The guide details the limitations of libraries, such as fastapi_mcp in this context, and demonstrates how to use the fastmcp and mcpauth libraries to implement an MCP server that supports dynamic registration, PKCE, and secure token exchange.

Step-by-step instructions are provided for both the Auth0 dashboard and API configuration

fastapi_mcp library limitations

For OAuth-based MCP servers, Claude.ai requires Dynamic Client Registration (DCR) support as per RFC 7591 and does not yet support a way for users to specify a client ID or secret manually.

The fastapi_mcp library, while excellent for many MCP use cases, has several limitations when it comes to Claude.ai's OAuth requirements:

  1. No Dynamic Client Registration Support : fastapi_mcp Requires pre-configured client IDs and secrets
  2. Static Configuration : Cannot handle Claude.ai’s dynamic application creation process
  3. MCP Inspector Compatibility : OAuth testing via MCP inspector fails with static configurations
  4. RFC 7591 Compliance : Lacks support for the Dynamic Client Registration standard required by Claude.ai
# This approach with fastapi_mcp does NOT work with Claude.ai OAuth
from fastapi_mcp import FastApiMCP, AuthConfig

# Static configuration - incompatible with Claude.ai
auth_config = AuthConfig(
    client_id="static-client-id", # Claude.ai doesn't support this
    client_secret="static-secret", # Claude.ai creates these dynamically
    setup_proxies=True,
)
Enter fullscreen mode Exit fullscreen mode

Using fastmcp and mcpauth Libraries

To properly support Claude.ai’s OAuth requirements, we use the fastmcp library with mcpauth For OAuth management:

pip install fastmcp mcpauth
Enter fullscreen mode Exit fullscreen mode

These libraries provide:

  • Dynamic Client Registration (RFC 7591) support
  • Claude.ai compatibility out of the box
  • MCP Inspector OAuth testing capabilities
  • Proper OAuth 2.0 flows with PKCE support

Auth0 Configuration for Dynamic Client Registration

Step 1: Enable OIDC Dynamic Application Registration

By default, Auth0 disables dynamic application registration for security reasons. To enable it:

  1. Navigate to Auth0 DashboardTenant Settings
  2. Go to Advanced Settings tab
  3. Find “Enable OIDC Dynamic Application Registration”
  4. Enable this setting

Warning : This setting allows third-party applications to dynamically register applications for your API. Ensure you have proper security measures in place.

Step 2: Grant Auth0 Management API Scopes for Connection Management

After enabling dynamic registration, you must ensure that your Auth0 Management API client has the correct permissions to manage connections. Specifically, you need to grant the update:connections and read:connections scopes to your Management API client. These scopes allow your automation or scripts to promote connections to domain-level and read connection details.

Granting Management API Scopes to Your Client

  1. Log in to the Auth0 Dashboard at https://manage.auth0.com/.
  2. Create a Machine to Machine Application :
  • Go to ApplicationsApplications in the sidebar.
  • Click Create Application.
  • Enter a name (e.g., “MCP Management Client”), select Machine to Machine Applications , and click Create.
  • Machine to Machine Applications require at least one authorized API. Select the Auth0 Management API

  • Select the permissions read:connections , update:connections , read:clients
  • Click Authorize to save the changes.
  • Note the Client ID and Client Secret from the settings page-> Basic Information Section

Your machine-to-machine application is now authorized to manage Auth0 connections using the Management API with the necessary scopes.

Your client now has the necessary permissions to manage Auth0 connections via the Management API.

Step 3: Obtain a Management API Token (with the required scopes):

Run the below command to obtain the management API Token

export AUTH0_DOMAIN=asdasda 
export AUTH0_CLIENT_ID=adsdasd 
export AUTH0_CLIENT_SECRET=asdasdasd

ACCESS_TOKEN=$(curl --silent --request POST \
      --url "https://${AUTH0_DOMAIN}/oauth/token" \
      --header 'content-type: application/x-www-form-urlencoded' \
      --data "grant_type=client_credentials" \
      --data "client_id=${AUTH0_CLIENT_ID}" \
      --data "client_secret=${AUTH0_CLIENT_SECRET}" \
      --data "audience=https://${AUTH0_DOMAIN}/api/v2/" \
      --data "scope=update:connections read:connections read:clients" \
      | grep -o '"access_token":"[^"]*"' | cut -d':' -f2 | tr -d '"')
Enter fullscreen mode Exit fullscreen mode

Verify the Client’s Granted Scopes :

curl --request GET \
--url "https://${AUTH0_DOMAIN}/api/v2/clients/${AUTH0_CLIENT_ID}" \
--header "authorization: Bearer ${ACCESS_TOKEN}"
Enter fullscreen mode Exit fullscreen mode

Check the grant_types and scopes fields in the response to ensure update:connections and read:connections are present.

Note: These scopes are only for managing Auth0 system resources (connections) and are not related to API resource access for end-user tokens.

Step 4: Create Domain-Level Connections

Claude.ai requires domain-level connections for third-party application authentication. By default, Auth0 connections are not domain-level.

Promote Connection to Domain-Level via Management API

Use the Auth0 Management API to promote your connection to domain-level:

# First, get your Management API token
ACCESS_TOKEN=$(curl --silent --request POST \
    --url "https://${AUTH0_DOMAIN}/oauth/token" \
    --header 'content-type: application/x-www-form-urlencoded' \
    --data "grant_type=client_credentials" \
    --data "client_id=${AUTH0_CLIENT_ID}" \
    --data "client_secret=${AUTH0_CLIENT_SECRET}" \
    --data "audience=https://${AUTH0_DOMAIN}/api/v2/" \
    --data "scope=update:connections read:connections" \
    | grep -o '"access_token":"[^"]*"' | cut -d':' -f2 | tr -d '"')

#To find your Google OAuth connection ID automatically, you can extract it from the API response using `jq` (a command-line JSON processor):

# List all connections and extract the ID for the google-oauth2 connection
GOOGLE_CONNECTION_ID=$(curl --silent --request GET \
    --url "https://${AUTH0_DOMAIN}/api/v2/connections" \
    --header "authorization: Bearer ${ACCESS_TOKEN}" \
    | jq -r '.[] | select(.name=="google-oauth2") | .id')
echo "Google OAuth connection ID: $GOOGLE_CONNECTION_ID"
Enter fullscreen mode Exit fullscreen mode

This command fetches all connections and filters for the one named "google-oauth2", outputting its "id" field. Use the value of $GOOGLE_CONNECTION_ID in the PATCH request to promote the connection to domain-level.

# promote the connection to domain-level
curl --request PATCH \
  --url "https://${AUTH0_DOMAIN}/api/v2/connections/${GOOGLE_CONNECTION_ID}" \
  --header "authorization: Bearer ${ACCESS_TOKEN}" \
  --header 'content-type: application/json' \
  --data '{ "is_domain_connection": true }'
Enter fullscreen mode Exit fullscreen mode

MCP Server Implementation with fastmcp

Server Setup with OAuth Support

from fastmcp import FastMCP
from mcpauth import MCPAuth
import asyncio
import logging

# Configure logging
logging.basicConfig(level=logging.INFO)
logger = logging.getLogger(__name__)

......
other code

# Initialize MCP server with OAuth
mcp_auth = MCPAuth(
    server=fetch_server_config(
        settings["issuer"],
        type=AuthServerType.OAUTH  # or AuthServerType.OAUTH
    )
)

app = FastAPI()

@app.get("/", operation_id="root")
async def root():
    """Root endpoint with API information"""

    return {
        "message": "Dev.to Markdown Publisher API",
        "version": "1.0.0",
    }

api_mcp = FastMCP.from_fastapi(app=app, name="API Server")

bearer_auth = mcp_auth.bearer_auth_middleware(
    "jwt", required_scopes=["read", "write"]
)

mcp_app = api_mcp.http_app(path='/mcp')

mcp_app.dependency_overrides = getattr(mcp_app, "dependency_overrides", {})
mcp_app.dependency_overrides[None] = bearer_auth


app = FastAPI(lifespan=tools_app.lifespan)

# Mount the MCP SSE app at /mcp
app.mount("/mcp", mcp_app)
# Add the metadata route for OAuth server discovery at /.well-known/oauth-authorization-server
app.add_route("/.well-known/oauth-authorization-server", mcp_auth.metadata_route(), methods=["GET"])

if __name__ == "__main__":
    # Run with OAuth support enabled
    uvicorn.run("app:app", host="0.0.0.0", port=8000, reload=True)
Enter fullscreen mode Exit fullscreen mode

Claude.ai Dynamic Application Registration

When Claude.ai connects to your MCP server with OAuth enabled, it automatically:

  1. Discovers OAuth Endpoints : Calls /.well-known/oauth-authorization-server
  2. Registers Dynamic Client : POSTs to /oauth/register endpoint
  3. Creates Auth0 Application : You’ll see “Claude.ai” app automatically created in Auth0 dashboard
  4. Initiates OAuth Flow : Redirects user for authentication
  5. Exchanges Tokens : Completes PKCE flow with dynamic client credentials

Viewing Dynamically Registered Applications

After Claude.ai connects, check your Auth0 dashboard:

  1. Go to Applications section
  2. Look for automatically created applications with names like:
  • “Claude.ai MCP Client”

These applications are created automatically by Claude.ai through the dynamic registration process.

Conclusion

Implementing OAuth authentication for MCP servers with Claude.ai requires careful attention to dynamic client registration requirements. The combination of fastmcp, mcpauth, and properly configured Auth0 settings enables seamless integration with Claude.ai's OAuth flows while maintaining security best practices.

Key takeaways:

  • Use fastmcp and mcpauth instead of fastapi_mcp for Claude.ai compatibility
  • Enable OIDC Dynamic Application Registration in Auth0
  • Promote connections to domain-level for third-party app support
  • Monitor Auth0 dashboard for automatically created Claude.ai applications
  • Test thoroughly with MCP Inspector before deploying to production

This setup ensures that your MCP server can authenticate users securely while providing the dynamic client registration capabilities that Claude.ai requires for OAuth integration.


Top comments (0)