{"record":{"id":"0369b23c5843b0c5","repo":"amruthpillai/reactive-resume","slug":"autherror","errorCode":"AuthError","errorMessage":"Unauthorized","messagePattern":"Unauthorized","errorType":"http","errorClass":"AuthError","httpStatus":401,"severity":"error","filePath":"apps/server/src/mcp/auth.ts","lineNumber":32,"sourceCode":"\t\t\tconst payload = await verifyOAuthToken(authHeader.slice(7));\n\t\t\tif (payload?.sub) return;\n\t\t} catch {\n\t\t\t// Invalid or expired token; fall through to API key auth.\n\t\t}\n\t}\n\n\tconst apiKey = request.headers.get(\"x-api-key\");\n\n\tif (apiKey) {\n\t\ttry {\n\t\t\tconst result = await auth.api.verifyApiKey({ body: { key: apiKey } });\n\t\t\tif (result.valid) return;\n\t\t} catch {\n\t\t\t// Invalid or malformed key; fall through to AuthError.\n\t\t}\n\t}\n\n\tthrow new AuthError();\n}\n","sourceCodeStart":14,"sourceCodeEnd":34,"githubUrl":"https://github.com/amruthpillai/reactive-resume/blob/3a5b12e2a40374a9571988701fcb75c5a1831c42/apps/server/src/mcp/auth.ts#L14-L34","documentation":"Thrown at the end of authenticateRequest after both credential paths have been tried and neither produced a valid principal. The function first attempts a Bearer OAuth token (authorization header) via verifyOAuthToken, then an x-api-key header via auth.api.verifyApiKey; if both are absent or invalid it throws AuthError (message 'Unauthorized'). It is the single gate for MCP HTTP requests, so any MCP client without a valid token or key is rejected.","triggerScenarios":"Calling any MCP endpoint (e.g. POST to the MCP transport route mounted in apps/server) with no Authorization and no x-api-key header; sending an expired/revoked Better Auth session bearer token; sending a malformed or deleted API key in x-api-key; sending a key with the wrong header name (e.g. 'api-key' instead of 'x-api-key').","commonSituations":"Local dev without logging in first; MCP client config (claude_desktop_config.json / cursor mcp config) missing the apiKey field; the user logged out and the cached bearer token expired; Better Auth API key was rotated or deleted server-side; reverse proxy stripping the Authorization header.","solutions":["Provide a Better Auth API key: send header 'x-api-key: <key>' generated from the app's API-key endpoint.","Or provide a valid session: send 'Authorization: Bearer <better-auth-session-token>' obtained by logging in through the web app.","Verify the header name is exactly 'x-api-key' (case-insensitive for header lookup, but spelling must match) and that the key is not wrapped in quotes or prefixed with 'Bearer '.","If using a Bearer token, confirm AUTH_SECRET on the server matches the secret that minted the token (mismatch silently invalidates the JWT)."],"exampleFix":"// before\nawait fetch(mcpUrl, { headers: { 'api-key': apiKey } });\n\n// after\nawait fetch(mcpUrl, { headers: { 'x-api-key': apiKey } });","handlingStrategy":"validation","validationCode":"// Validate the request will authenticate before sending.\nfunction buildAuthHeaders(apiKey?: string, bearerToken?: string): Record<string, string> {\n  if (bearerToken && bearerToken.startsWith('Bearer ')) return { authorization: bearerToken };\n  if (bearerToken && bearerToken.length > 0) return { authorization: `Bearer ${bearerToken}` };\n  if (apiKey && apiKey.trim().length > 0) return { 'x-api-key': apiKey.trim() };\n  throw new Error('MCP client must provide either a Better Auth bearer token or an x-api-key.');\n}","typeGuard":"function hasMcpCredentials(opts: { apiKey?: string; bearerToken?: string }): boolean {\n  return (!!opts.bearerToken && opts.bearerToken.length > 0) || (!!opts.apiKey && opts.apiKey.trim().length > 0);\n}","tryCatchPattern":null,"preventionTips":["Centralize MCP header construction in one client wrapper so every call carries valid auth.","Treat HTTP 401 from the MCP endpoint as 'credentials invalid' and surface a re-login/re-key prompt rather than retrying.","Store the API key in the platform secret store, never in source.","When rotating AUTH_SECRET, invalidate and reissue all API keys and bearer tokens."],"tags":["mcp","authentication","api-key","better-auth","headers"],"backgroundTag":null,"analyzedSha":"3a5b12e2a40374a9571988701fcb75c5a1831c42","analyzedAt":"2026-08-12T22:31:22.666Z","schemaVersion":2},"datasetVersion":"2026-08-12T23:17:12.415Z"}