{"record":{"id":"3e73d1b87ca63e4a","repo":"abhigyanpatwari/GitNexus","slug":"32001","errorCode":"-32001","errorMessage":"Unauthorized","messagePattern":"Unauthorized","errorType":"http","errorClass":null,"httpStatus":401,"severity":"error","filePath":"gitnexus/src/mcp/http-transport.ts","lineNumber":109,"sourceCode":"    // we create a same-length dummy so the comparison always runs in full.\n    let valid = false;\n    if (typeof header === 'string') {\n      const a = Buffer.from(header);\n      const b = Buffer.from(expected);\n      if (a.length === b.length) {\n        valid = timingSafeEqual(a, b);\n      } else {\n        // Different lengths — run dummy comparison to preserve constant time.\n        timingSafeEqual(Buffer.alloc(b.length), b);\n      }\n    }\n\n    if (valid) {\n      next();\n      return;\n    }\n\n    res.status(401).json({\n      jsonrpc: '2.0',\n      error: { code: -32001, message: 'Unauthorized' },\n      id: null,\n    });\n  };\n}\n\n/**\n * Returns true when an Origin should be allowed by the no-auth (loopback-only)\n * CORS policy — i.e. it is absent (non-browser caller) or a loopback origin.\n *\n * WHATWG URL keeps the brackets on IPv6 literals\n * (`new URL('http://[::1]/').hostname === '[::1]'`) and canonicalizes the\n * IPv4-mapped loopback to `[::ffff:7f00:1]`; loopback IPv4 is the whole\n * 127.0.0.0/8 block — so all of those forms are matched explicitly.\n */\nexport function isLoopbackOrigin(origin: string | undefined): boolean {\n  if (!origin) return true; // no Origin → non-browser caller; CORS is not the control there","sourceCodeStart":91,"sourceCodeEnd":127,"githubUrl":"https://github.com/abhigyanpatwari/GitNexus/blob/aac7515d2a8c50a1f8f923c6fb77218b333560d6/gitnexus/src/mcp/http-transport.ts#L91-L127","documentation":"The MCP HTTP transport supports optional Bearer auth: when McpHttpOptions.authToken is configured, every request must carry 'Authorization: Bearer <token>' exactly. The comparison is constant-time (timingSafeEqual with a length-matched dummy), and a missing, malformed, or wrong token gets a JSON-RPC-formatted 401 with code -32001. When no authToken is set, all requests pass through.","triggerScenarios":"Connecting an MCP client to the gitnexus streamable-HTTP endpoint with the Authorization header unset, mistyped, or with a scheme/prefix mistake ('token' instead of 'Bearer token'), while the server runs with an authToken configured.","commonSituations":"Token rotated on the server but the client config kept the old value; a reverse proxy stripping the Authorization header; trailing newline/quote pollution from .env files; browser-based clients that cannot set the header on the first request.","solutions":["Send the identical token: header 'Authorization: Bearer <authToken>'","Re-copy the token from the server configuration and watch for trailing newlines or quotes in .env values","If a proxy fronts the server, configure it to forward the Authorization header","For trusted local use, run the server without authToken (loopback-only no-auth mode)"],"exampleFix":"# before\nclient = MCPClient('http://127.0.0.1:4747/mcp')  # no header → 401 -32001\n\n# after\nclient = MCPClient('http://127.0.0.1:4747/mcp',\n                    headers={'Authorization': f'Bearer {TOKEN}'})","handlingStrategy":"validation","validationCode":"const headers = authToken\n  ? { Authorization: `Bearer ${authToken.trim()}` }\n  : {};\nawait fetch('http://127.0.0.1:4747/mcp', {\n  method: 'POST',\n  headers,\n  body: JSON.stringify(initializeRequest),\n});","typeGuard":null,"tryCatchPattern":"// on a JSON-RPC 401 with code -32001: refresh the token from config and retry once\nif (res.status === 401 && body?.error?.code === -32001) {\n  token = loadTokenFresh();\n  return request(path, payload, /* attempt */ 2);\n}","preventionTips":["Load the bearer token from the same config the server uses; trim whitespace/newlines","Verify proxies forward the Authorization header","For loopback-only local use, run the server without authToken instead of weakening the client"],"tags":["auth","http","mcp","bearer-token","http-401"],"backgroundTag":"authentication-failed","analyzedSha":"aac7515d2a8c50a1f8f923c6fb77218b333560d6","analyzedAt":"2026-08-20T23:29:22.980Z","contentChangedAt":"2026-08-20T23:29:22.980Z","schemaVersion":2},"datasetVersion":"2026-09-14T05:17:10.506Z"}