{"record":{"id":"a96f7c2b2c520e0d","repo":"actualbudget/actual","slug":"authorization-failed-missing-code","errorCode":null,"errorMessage":"Authorization failed: missing code.","messagePattern":"Authorization failed: missing code\\.","errorType":"http","errorClass":null,"httpStatus":400,"severity":"error","filePath":"packages/sync-server/src/app-enablebanking/app-enablebanking.ts","lineNumber":107,"sourceCode":"  );\n\n  return {\n    session_id: session.session_id,\n    accounts: accountsWithBalances,\n    aspsp: session.aspsp,\n  };\n}\n\n// Auth callback from bank redirect — must be before validateSessionMiddleware\n// since the bank redirects here directly (no auth token available)\napp.get('/auth_callback', async (req: Request, res: Response) => {\n  const code = typeof req.query.code === 'string' ? req.query.code : undefined;\n  const state =\n    typeof req.query.state === 'string' ? req.query.state : undefined;\n\n  if (!code) {\n    res\n      .status(400)\n      .send(\n        '<html><body><p>Authorization failed: missing code.</p></body></html>',\n      );\n    return;\n  }\n\n  if (!state) {\n    res\n      .status(400)\n      .send(\n        '<html><body><p>Authorization failed: missing state parameter.</p></body></html>',\n      );\n    return;\n  }\n\n  try {\n    const session = await enableBankingService.createSession(code);\n    debug(","sourceCodeStart":89,"sourceCodeEnd":125,"githubUrl":"https://github.com/actualbudget/actual/blob/d4334cb6e6123f4d3bcea1ad6166608884c7e658/packages/sync-server/src/app-enablebanking/app-enablebanking.ts#L89-L125","documentation":"The Enable Banking OAuth callback endpoint requires the authorization server to append a `code` query parameter to the redirect URL. When the callback request arrives without it, the handler immediately returns HTTP 400 with this HTML page instead of exchanging the code for tokens. It signals that the OAuth redirect never carried an authorization code, so the flow cannot continue.","triggerScenarios":"The bank/ASPSP redirected the user to /enablebanking-handler (callback) without a `code` query parameter — e.g. the user hit the callback URL directly, the authorization request was malformed, or the provider errored before issuing a code.","commonSituations":"Developers bookmarking or re-opening the callback URL manually; misconfigured redirect URIs where the provider strips query params; Enable Banking authorization failing at the provider side and redirecting back with only an error parameter; proxies rewriting the URL and dropping the query string.","solutions":["Restart the OAuth flow from the beginning (initiate a new authorization request) instead of reusing/reloading the callback URL","Verify the authorization request URL and redirect_uri registered with Enable Banking match exactly, so the provider returns a code","Check whether the provider redirected with an `error` query param and surface that to the user","Inspect any reverse proxy / URL rewriting in front of the sync-server that could strip query parameters"],"exampleFix":"// before (reloading stale callback URL)\nGET https://server/enablebanking-handler  -> 400 missing code\n// after (restart flow)\nGET https://server/enablebanking-handler/init → redirect to bank → callback includes ?code=...&state=...","handlingStrategy":"validation","validationCode":"const url = new URL(callbackUrl);\nif (!url.searchParams.get('code')) {\n  throw new Error('callback URL has no code param; restart the OAuth flow');\n}","typeGuard":"function hasCode(q: Record<string, unknown>): q is { code: string } {\n  return typeof q.code === 'string' && q.code.length > 0;\n}","tryCatchPattern":"null","preventionTips":["Never load or bookmark the callback URL directly — always arrive via the provider redirect","Log the full callback query string when debugging OAuth flows","Verify redirect_uri matches the provider registration exactly","Surface provider `error` query params to the user instead of a blank failure"],"tags":["oauth","http-400","enablebanking","missing-parameter"],"backgroundTag":"oauth-missing-authorization-code","analyzedSha":"d4334cb6e6123f4d3bcea1ad6166608884c7e658","analyzedAt":"2026-08-29T01:02:11.213Z","schemaVersion":2},"datasetVersion":"2026-08-29T02:17:18.158Z"}