Replies: 3 comments 12 replies
|
I haven't used Auth0's CIMD specifically, but here's what I'd check based on how FastMCP's 1. Verify your Auth0 CIMD metadata endpoint responds correctly FastMCP's remote auth discovery hits {
"issuer": "https://your-tenant.auth0.com/",
"authorization_endpoint": "https://your-tenant.auth0.com/authorize",
"token_endpoint": "https://your-tenant.auth0.com/oauth/token",
"registration_endpoint": "https://your-tenant.auth0.com/oidc/register"
}2. Enable debug logging to see what's failing import logging
logging.basicConfig(level=logging.DEBUG)
# Also check FastMCP's internal logs
import fastmcp
fastmcp.settings.log_level = 'DEBUG'This should show you the exact HTTP request/response that fails. 3. Common Auth0 + MCP issues:
4. Workaround if CIMD isn't working: You can still use from fastmcp.server.auth import OAuthProxy
auth = OAuthProxy(
authorize_url='https://your-tenant.auth0.com/authorize',
token_url='https://your-tenant.auth0.com/oauth/token',
client_id='YOUR_CLIENT_ID',
client_secret='YOUR_CLIENT_SECRET',
)@scastria If you can share the error from the debug logs (even sanitized), that would help narrow it down. |
|
@scastria Follow-up after re-reading the FastMCP source and docs — including corrections to my earlier comment. Corrections to my previous post
Two different “CIMD” layers (easy to conflate)
What FastMCP documents for Auth0 today Auth0 is documented under the OIDC proxy ( from fastmcp import FastMCP
from fastmcp.server.auth.providers.auth0 import Auth0Provider
auth = Auth0Provider(
config_url="https://YOUR_TENANT.auth0.com/.well-known/openid-configuration",
client_id="YOUR_APP_CLIENT_ID",
client_secret="YOUR_APP_CLIENT_SECRET",
audience="https://YOUR_API_IDENTIFIER",
base_url="https://your-server.example.com",
)
mcp = FastMCP("My Server", auth=auth)
If you specifically want That model assumes MCP clients authenticate directly with Auth0 and send Bearer tokens to your server. Minimum setup from the docs: from fastmcp import FastMCP
from fastmcp.server.auth import RemoteAuthProvider
from fastmcp.server.auth.providers.jwt import JWTVerifier
from pydantic import AnyHttpUrl
token_verifier = JWTVerifier(
jwks_uri="https://YOUR_TENANT.auth0.com/.well-known/jwks.json",
issuer="https://YOUR_TENANT.auth0.com/",
audience="https://YOUR_API_IDENTIFIER",
)
auth = RemoteAuthProvider(
token_verifier=token_verifier,
authorization_servers=[AnyHttpUrl("https://YOUR_TENANT.auth0.com/")],
base_url="https://your-server.example.com",
)
mcp = FastMCP("My Server", auth=auth)Things I would verify in your environment (these are common silent-failure causes):
I don’t know of a public “it works” report yet — your question is still the right one. If you can say whether you want (A) clients → Auth0 directly, or (B) clients → FastMCP proxy → Auth0, plus a sanitized |
|
@scastria Your debugging trail matches what the FastMCP source and MCP spec actually specify. Here is a verified breakdown. 1. You are correct:
|
| Field | Why it matters |
|---|---|
registration_endpoint |
Classic MCP clients use RFC 7591 DCR unless using CIMD |
issuer |
Must align with tokens you validate in JWTVerifier |
| CIMD / Auth for MCP setup | Auth0’s GA flow often requires tenant admin to approve a client CIMD URL before registration works — not anonymous DCR |
Auth0’s May 2026 CIMD GA is admin-gated (changelog). If Cursor is attempting dynamic registration and Auth0 expects a pre-registered CIMD document, registration fails silently from the MCP server’s perspective (you only see another 401 on /mcp).
Also check token shape: JWTVerifier only works for JWT access tokens with matching iss / aud. Auth0 often needs an audience (API identifier) to issue JWTs; opaque tokens need introspection instead.
5. scopes_supported: [] in your PRM
Your PRM shows "scopes_supported": []. That is whatever you passed into RemoteAuthProvider / JWTVerifier. Consider advertising scopes explicitly if Auth0 requires them for consent/API access:
JWTVerifier(..., required_scopes=["openid", "offline_access", ...])
# and/or RemoteAuthProvider(..., scopes_supported=[...])6. Breakpoints (verified file paths)
Server (FastMCP):
| Location | What you’ll see |
|---|---|
fastmcp/server/auth/middleware.py → RequireAuthMiddleware._send_auth_error |
The 401 + WWW-Authenticate your logs show |
mcp.server.auth.middleware.bearer_auth (SDK) |
Token extraction / missing token |
RemoteAuthProvider.verify_token → token_verifier.verify_token |
Whether a Bearer token is accepted |
OAuthProxy path (for comparison):
| Location | What you’ll see |
|---|---|
fastmcp/server/auth/oauth_proxy/proxy.py |
DCR, /authorize, /token, CIMD handling |
Client: Cursor is closed-source Node; you won’t debug its OAuth FSM in FastMCP. Use mitmproxy/Charles to watch traffic to login.dev.WXYZ.com after the initial /mcp 401. For a FastMCP-native client repro: fastmcp/client/auth/oauth.py.
7. Practical recommendation
- Production today:
Auth0Provider/OAuthProxy(you already have this working) is the supported Auth0 integration. RemoteAuthProviderexperiment: Stock behavior is PRM-only on the MCP server; your AS forwarder is fine as optional sugar. The remaining issue is almost certainly Auth0-side discovery/registration (DCR vs CIMD vs admin approval), not missing routes on localhost.
If you can paste (redacted):
- The
WWW-Authenticateheader from thePOST /mcp401, and - The JSON from
https://login.dev.WXYZ.com/.well-known/oauth-authorization-server(especiallyregistration_endpoint,issuer,code_challenge_methods_supported),
we can narrow whether this is a Cursor+DCR issue vs Auth0 CIMD configuration.
Uh oh!
There was an error while loading. Please reload this page.
Auth0 added support for CIMD registration in May: https://auth0.com/changelog#6SeJmK4wyY7sizFRsLJvvq so I think I no longer have to use the OAuthProxy. But when I try it, it just fails with no helpful error messages to debug. Has anybody gotten RemoteAuthProvider to work with Auth0 yet?
All reactions