{"record":{"id":"70d253f49688f9df","repo":"decolua/9router","slug":"no-authorization-code-received-70d253","errorCode":null,"errorMessage":"No authorization code received","messagePattern":"No authorization code received","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"src/lib/oauth/services/codex.js","lineNumber":124,"sourceCode":"        }, 300000);\n\n        const checkInterval = setInterval(() => {\n          if (callbackParams) {\n            clearInterval(checkInterval);\n            clearTimeout(timeout);\n            resolve();\n          }\n        }, 100);\n      });\n\n      close();\n\n      if (callbackParams.error) {\n        throw new Error(callbackParams.error_description || callbackParams.error);\n      }\n\n      if (!callbackParams.code) {\n        throw new Error(\"No authorization code received\");\n      }\n\n      spinner.start(\"Exchanging code for tokens...\");\n\n      // Exchange code for tokens (Codex uses form-urlencoded)\n      const tokens = await this.exchangeCode(callbackParams.code, redirectUri, codeVerifier, \"application/x-www-form-urlencoded\");\n\n      spinner.text = \"Saving tokens to server...\";\n\n      // Save tokens to server\n      await this.saveTokens(tokens);\n\n      spinner.succeed(\"Codex connected successfully!\");\n      return true;\n    } catch (error) {\n      spinner.fail(`Failed: ${error.message}`);\n      throw error;\n    }","sourceCodeStart":106,"sourceCodeEnd":142,"githubUrl":"https://github.com/decolua/9router/blob/90b52e06ffd666b7929554211474d01588f6b1f8/src/lib/oauth/services/codex.js#L106-L142","documentation":"In CodexService.connect() (src/lib/oauth/services/codex.js:124), the OAuth callback arrived without an error parameter but also without the expected `code` query parameter. The local server captured callbackParams but OpenAI's redirect did not deliver an authorization code, so the PKCE code exchange cannot proceed and the library aborts.","triggerScenarios":"Calling connect() and receiving a callback whose query string lacks `code` — typically a redirect to the callback URL with no OAuth params at all (user manually navigated to http://localhost:1455/auth/callback, or a browser extension/proxy stripped query params), or the provider returned an unexpected response shape that bypassed the error check.","commonSituations":"The user types or bookmarks the callback URL directly while the local server is listening; a security plugin or corporate proxy rewrites the redirect and drops the query string; the browser opens the callback twice and the second (code-less) hit overwrites callbackParams via the polling checkInterval.","solutions":["Re-run connect() and let the browser redirect happen naturally; do not navigate to the callback URL manually.","Log callbackParams (Object.keys) at the local-server handler to see exactly what the provider sent back.","Check for browser extensions or proxies that strip query parameters on localhost redirects and disable them.","Guard the param setter in startLocalServer to ignore subsequent code-less callbacks so a duplicate request cannot overwrite a good one."],"exampleFix":"// before\ncallbackParams = params;\n// after: keep first valid callback\ncallbackParams = callbackParams || params;\nif (params.code) callbackParams = params;","handlingStrategy":"validation","validationCode":"const params = new URLSearchParams(callbackUrl.split(\"?\")[1] || \"\");\nif (!params.get(\"code\") && !params.get(\"error\")) {\n  console.error(\"Callback had neither code nor error — check for param-stripping proxies/extensions\");\n}","typeGuard":"function hasAuthorizationCode(params) {\n  return typeof params === \"object\" && params !== null && typeof params.code === \"string\" && params.code.length > 0;\n}","tryCatchPattern":"try {\n  await codexService.connect();\n} catch (err) {\n  if (err.message === \"No authorization code received\") {\n    console.error(\"The redirect back to localhost carried no ?code=. Disable extensions/proxies that strip query params and retry.\");\n  } else throw err;\n}","preventionTips":["Never navigate to the callback URL manually while the flow is waiting.","Ignore duplicate/code-less callback hits in the local server handler so they cannot overwrite a valid one.","Log the raw callback URL once to diagnose param stripping early.","Test the flow in a clean browser profile when corporate proxies are present."],"tags":["oauth","codex","callback","missing-parameter"],"backgroundTag":"oauth-callback-missing-code","analyzedSha":"90b52e06ffd666b7929554211474d01588f6b1f8","analyzedAt":"2026-08-30T21:05:45.952Z","schemaVersion":2},"datasetVersion":"2026-08-30T23:17:21.991Z"}