fix: serve OAuth AS metadata at /.well-known/openid-configuration

ChatGPT uses OIDC discovery to bootstrap the OAuth flow: it fetches
/.well-known/openid-configuration to find the registration_endpoint,
authorization_endpoint, and token_endpoint before attempting DCR.
Without this endpoint responding, it cannot proceed and reports
'does not implement OAuth'.

Serve the same AS metadata at the OIDC discovery URL so OIDC-first
clients can bootstrap the full OAuth 2.1 + DCR flow.
This commit is contained in:
jubnl
2026-05-05 14:25:05 +02:00
parent 001cc6431b
commit f9db7e1104
+20
View File
@@ -409,11 +409,31 @@ export function createApp(): express.Application {
app.use((req: Request, res: Response, next: NextFunction) => {
const isMetadataPath =
req.path === '/.well-known/oauth-authorization-server' ||
req.path === '/.well-known/openid-configuration' ||
req.path.startsWith('/.well-known/oauth-protected-resource');
if (isMetadataPath && !isAddonEnabled(ADDON_IDS.MCP)) return res.status(404).end();
getMetaRouter()(req, res, next);
});
// ChatGPT (and other OIDC-first clients) bootstrap OAuth discovery via
// /.well-known/openid-configuration. Serve the same AS metadata there so
// they can find the registration_endpoint, authorization_endpoint, etc.
app.get('/.well-known/openid-configuration', (_req: Request, res: Response) => {
const base = (getAppUrl() || 'http://localhost:3001').replace(/\/+$/, '');
res.json({
issuer: base,
authorization_endpoint: `${base}/oauth/authorize`,
token_endpoint: `${base}/oauth/token`,
revocation_endpoint: `${base}/oauth/revoke`,
registration_endpoint: `${base}/oauth/register`,
response_types_supported: ['code'],
grant_types_supported: ['authorization_code', 'refresh_token'],
code_challenge_methods_supported: ['S256'],
token_endpoint_auth_methods_supported: ['client_secret_post', 'none'],
scopes_supported: ALL_SCOPES,
});
});
// SDK authorize handler: validates OAuth params, calls provider.authorize() which redirects
// to the SPA consent page at /oauth/consent
app.use('/oauth/authorize', mcpAddonGate, authorizationHandler({ provider: trekOAuthProvider }));