mastra-ai/mastra · error
auth callback rejected (invalid state/token); 400 HTML failu
Error message
auth callback rejected (invalid state/token); 400 HTML failure page returned
What it means
During the interactive `mastra auth login` OAuth-style flow, the local HTTP callback validates the returned state parameter and required fields (token, user, org). If the state does not match the CSRF value the CLI generated, or token/user/org are missing, it responds with a 400 HTML failure page and throws this error, aborting login to prevent CSRF/token-injection attacks.
Source
Thrown at packages/cli/src/commands/auth/credentials.ts:304
handleAbort();
return;
}
if (options.skipOnInput) {
stopListeningForSkip = listenForSkipInput(() => finish(() => reject(new LoginCancelledError())));
}
server.on('request', (req, res) => {
const url = new URL(req.url!, `http://localhost:${port}`);
if (url.pathname === '/callback') {
const callbackState = url.searchParams.get('state');
const token = url.searchParams.get('token');
const refreshToken = url.searchParams.get('refresh_token');
const userParam = url.searchParams.get('user');
const orgId = url.searchParams.get('org');
if (callbackState !== state || !token || !userParam || !orgId) {
res.writeHead(400, { 'Content-Type': 'text/html' });
res.end(callbackPage({ success: false }));
return;
}
const user = JSON.parse(decodeURIComponent(userParam));
res.writeHead(200, { 'Content-Type': 'text/html', Connection: 'close' });
res.end(callbackPage({ success: true }));
finish(() => resolve({ token, refreshToken, user, organizationId: orgId }));
}
});
});
const creds: Credentials = {
token: result.token,
...(result.refreshToken ? { refreshToken: result.refreshToken } : {}),
user: result.user,View on GitHub (pinned to 75dd419e61)
Solutions
- Abort the failed browser tab and restart cleanly with `mastra auth login`, completing the flow in the newly opened tab without reusing old URLs.
- Ensure only one `mastra auth login` runs at a time.
- Paste the full callback URL including all query parameters if completing manually.
- Disable browser extensions that strip query strings, or try another browser.
Example fix
// before (stale tab reused) http://localhost:PORT/callback?state=OLD_STATE... # 400 failure page // after mastra auth login # fresh state, use the newly opened tab only
Defensive patterns
Strategy: try-catch
Type guard
function isLoginStateError(err: unknown): boolean {
return err instanceof Error &&
err.message.includes('auth callback rejected');
} Try / catch
try {
await login(signal, options);
} catch (err) {
if (isLoginStateError(err)) {
console.error('Login callback invalid — restart the flow: `mastra auth login`, and use only the newly opened browser tab.');
return login(signal, options); // single clean retry
}
throw err;
} Prevention
- Never reuse or bookmark callback URLs from a previous login attempt.
- Run only one `mastra auth login` at a time.
- Complete login promptly in the tab the CLI opened; state expires with the CLI process.
- Disable extensions that rewrite or strip URL query parameters.
When it happens
Trigger: The browser callback URL hit the local server with state != the generated state, or with missing token / user / org query params — e.g. user pasted a truncated URL, bookmarked a stale callback URL, the login page was opened twice, or a redirect dropped parameters.
Common situations: Re-opening an old login tab after the CLI restarted (state mismatch); copying only part of the callback URL; browser extensions stripping query params; concurrent `mastra auth login` runs clobbering each other's state; firewall/alternate port sending the callback to the wrong CLI instance.
Related errors
- Invalid state redirect suffix
- Invalid state token format
- Invalid state token signature
- Invalid state token format
- Invalid or tampered state token
AI-assisted analysis of mastra-ai/mastra@75dd419e61 (2026-08-30).
Data as JSON: /api/errors/3b7e1131c5a37e66.
Report an issue: GitHub.