Skip to main content
Glama

ChatGPT App with OAuth2 + MCP + Privy

by Jahnik
CRITICAL_FINDINGS.md7.87 kB
# Critical Findings: OAuth Authentication Comparison ## The Core Issue: Why ChatGPT Reports "Connection Problem" ### Summary The **mcp** implementation uses **opaque (unvalidatable) tokens**, while **mcp2** uses **JWT tokens with proper OAuth infrastructure**. ChatGPT likely rejects mcp because it cannot validate tokens without connecting to the server every time. --- ## Critical Difference #1: Token Format ### mcp2 (Correct for ChatGPT): ```typescript // JWT token - self-validating with cryptographic signature const accessToken = jwt.sign( { sub: privyUserId, scope: scopes.join(' '), aud: audience, // AUDIENCE CLAIM client_id: clientId, }, config.jwt.privateKey, { algorithm: 'RS256', // RSA with SHA-256 expiresIn: '1h', issuer: serverUrl, // ISSUER CLAIM keyid: 'key-1', } ); ``` **Result**: Token is a signed JWT that ChatGPT can validate independently using the public key from JWKS endpoint. ### mcp (Problem for ChatGPT): ```typescript // Opaque random token - cannot be validated without server const accessToken = randomBytes(32).toString("base64url"); // "Q3d4...Jk2=" <- just random bytes, no claims, no signature ``` **Result**: Token is meaningless without server. ChatGPT has NO WAY to validate it. --- ## Critical Difference #2: JWKS Endpoint ### mcp2 Has: ``` GET /.well-known/jwks.json ``` Returns: ```json { "keys": [{ "kty": "RSA", "use": "sig", "alg": "RS256", "kid": "key-1", "n": "...", "e": "AQAB" }] } ``` **What ChatGPT does**: Downloads the public key, validates JWT signature offline. ### mcp Missing: **No JWKS endpoint at all.** **What ChatGPT tries**: 1. Look for JWKS endpoint ✗ (not found) 2. Fall back to introspection ✗ (not implemented) 3. Give up: "connection problem" --- ## Critical Difference #3: Token Validation at MCP Endpoint ### mcp2 (Proper JWT Validation): ```typescript // Middleware validates JWT cryptographically const decoded = jwt.verify(token, config.jwt.publicKey, { algorithms: ['RS256'], issuer: config.server.baseUrl, // CHECKED audience: config.server.baseUrl, // CHECKED - CRITICAL! }); // Can validate without touching token store req.auth = { token, decoded, userId: decoded.sub }; ``` **Security**: JWT is self-validating. Public key proves authenticity. Cannot be forged. ### mcp (Insecure Validation): ```typescript // Middleware looks up token in memory map const validation = validateAccessToken(token); // Just checks: is token in map? is it expired? // NO cryptographic validation! ``` **Security Problem**: Any client can send any opaque token. If server crashes/restarts, all tokens become valid (empty map!). --- ## Critical Difference #4: Token Introspection ### mcp2: ```typescript // Implements RFC 7662 token introspection tokenRouter.post('/introspect', async (req, res) => { const decoded = jwt.verify(token, config.jwt.publicKey, ...); res.json({ active: true, sub: decoded.sub, scope: decoded.scope, client_id: decoded.client_id, exp: decoded.exp, iat: decoded.iat, iss: decoded.iss, aud: decoded.aud, }); }); ``` **Use case**: When ChatGPT receives 401, it can ask "is this token still valid?" without making MCP request. ### mcp: **Not implemented.** --- ## Root Cause: The "Connection Problem" ### ChatGPT OAuth Client Flow with mcp2: ``` 1. User logs in via OAuth 2. ChatGPT receives JWT access token 3. ChatGPT calls GET /.well-known/jwks.json 4. ChatGPT gets server's public key 5. ChatGPT validates token signature: ✓ Valid! 6. ChatGPT calls /mcp with token 7. Server validates JWT: ✓ Matches! 8. Tools execute successfully ``` ### ChatGPT OAuth Client Flow with mcp: ``` 1. User logs in via OAuth 2. ChatGPT receives opaque token "Q3d4...Jk2=" 3. ChatGPT calls GET /.well-known/jwks.json 4. 404 Not Found ✗ 5. ChatGPT calls POST /.well-known/oauth-authorization-server 6. Returns metadata WITHOUT jwks_uri ✗ 7. ChatGPT tries token introspection endpoint 8. 404 Not Found ✗ 9. ChatGPT cannot validate token 10. ChatGPT rejects connection: "connection problem" ``` --- ## The Exact Problem Lines ### mcp Missing Lines: **File: `/Users/jahnik/index-network/mcp/src/oauth.ts`** This function returns metadata: ```typescript export function authorizationServerMetadata() { return { issuer, authorization_endpoint: ..., token_endpoint: ..., registration_endpoint: ..., // ❌ MISSING: jwks_uri scopes_supported: ..., // ... other fields }; } ``` **What it should have**: ```typescript jwks_uri: `${issuer}/.well-known/jwks.json`, ``` And then implement the endpoint: ```typescript export function getJWKS() { return { keys: [ { kty: "RSA", use: "sig", alg: "RS256", kid: "key-1", n: base64urlEncode(publicKey.n), e: base64urlEncode(publicKey.e) } ] }; } ``` --- ## The Fix Options ### Option A: Upgrade mcp to mcp2 Architecture (Recommended) - Switch from opaque tokens to JWT - Add JWKS endpoint - Add token introspection - Proper OAuth metadata **Effort**: Rewrite token handling layer (medium) **Benefit**: Full ChatGPT compatibility, industry standard ### Option B: Add Missing Endpoints to mcp 1. Convert opaque tokens to JWT (see mcp2 for reference) 2. Add `/.well-known/jwks.json` endpoint 3. Add `/token/introspect` endpoint 4. Update metadata to include `jwks_uri` **Effort**: Add OAuth infrastructure (high) **Benefit**: Maintains opaque token approach but fixes immediate issues ### Option C: Hybrid Approach - Keep mcp's opaque tokens for now - Implement JWKS endpoint (fake JWT wrapping) - Add introspection for immediate ChatGPT fix - Plan migration to mcp2 architecture **Effort**: Quick patch (low) **Benefit**: ChatGPT works while planning upgrade --- ## Verification Checklist To verify which implementation ChatGPT can actually use: ### For mcp2: - [ ] GET /.well-known/jwks.json returns public key? (Should see `kty: RSA`) - [ ] POST /token returns JWT token? (Should start with `eyJ...`) - [ ] JWT header has `kid: key-1`? - [ ] JWT payload has `aud` claim? - [ ] POST /mcp with JWT token works? ### For mcp: - [ ] GET /.well-known/oauth-authorization-server returns `jwks_uri`? - [ ] POST /token returns what format? (Random bytes vs JWT?) - [ ] GET /.well-known/jwks.json exists? - [ ] POST /token/introspect endpoint exists? --- ## Key Code Differences ### Where mcp2 wins - Token Endpoint: **mcp2**: `src/server/oauth/token.ts` lines 236-275 ```typescript function issueAccessToken({...}) { const accessToken = jwt.sign({...}, config.jwt.privateKey, { algorithm: 'RS256', expiresIn: '1h', issuer: config.jwt.issuer, keyid: 'key-1', }); // Returns: accessToken (JWT) } ``` **mcp**: `src/oauth.ts` lines 549-593 ```typescript function issueTokens(payload) { const accessToken = randomBytes(32).toString("base64url"); // Returns: accessToken (opaque) } ``` ### Where mcp2 wins - Authentication Middleware: **mcp2**: `src/server/middleware/auth.ts` lines 27-82 ```typescript const decoded = jwt.verify(token, config.jwt.publicKey, { algorithms: [config.jwt.algorithm], issuer: config.jwt.issuer, audience: config.server.baseUrl, // ← This validates who token is for }); ``` **mcp**: `src/auth.ts` lines 58 ```typescript const validation = validateAccessToken(token); // Just a Map lookup ``` --- ## Recommendation **Use mcp2 for production ChatGPT integration.** The architectural differences are fundamental: - mcp2 uses industry-standard JWT tokens - mcp uses custom opaque tokens with server-side storage - For ChatGPT compatibility, you need jwks_uri + introspection - mcp2 already has both The "connection problem" is not a bug - it's correct behavior from ChatGPT refusing unvalidatable tokens.

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/Jahnik/mcp2'

If you have feedback or need assistance with the MCP directory API, please join our Discord server