actualbudget/actual · error
Authorization failed: missing code.
Error message
Authorization failed: missing code.
What it means
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.
Source
Thrown at packages/sync-server/src/app-enablebanking/app-enablebanking.ts:107
);
return {
session_id: session.session_id,
accounts: accountsWithBalances,
aspsp: session.aspsp,
};
}
// Auth callback from bank redirect — must be before validateSessionMiddleware
// since the bank redirects here directly (no auth token available)
app.get('/auth_callback', async (req: Request, res: Response) => {
const code = typeof req.query.code === 'string' ? req.query.code : undefined;
const state =
typeof req.query.state === 'string' ? req.query.state : undefined;
if (!code) {
res
.status(400)
.send(
'<html><body><p>Authorization failed: missing code.</p></body></html>',
);
return;
}
if (!state) {
res
.status(400)
.send(
'<html><body><p>Authorization failed: missing state parameter.</p></body></html>',
);
return;
}
try {
const session = await enableBankingService.createSession(code);
debug(View on GitHub (pinned to d4334cb6e6)
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
Example fix
// before (reloading stale callback URL) GET https://server/enablebanking-handler -> 400 missing code // after (restart flow) GET https://server/enablebanking-handler/init → redirect to bank → callback includes ?code=...&state=...
Defensive patterns
Strategy: validation
Validate before calling
const url = new URL(callbackUrl);
if (!url.searchParams.get('code')) {
throw new Error('callback URL has no code param; restart the OAuth flow');
} Type guard
function hasCode(q: Record<string, unknown>): q is { code: string } {
return typeof q.code === 'string' && q.code.length > 0;
} Try / catch
null
Prevention
- 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
When it happens
Trigger: 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.
Common situations: 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.
Related errors
- Authorization failed: missing state parameter.
- Authorization failed. You can close this window and try agai
- No token received.
- Parameter ${name} not provided to query
- NOT_CONFIGURED
AI-assisted analysis of actualbudget/actual@d4334cb6e6 (2026-08-29).
Data as JSON: /api/errors/a96f7c2b2c520e0d.
Report an issue: GitHub.