mastra-ai/mastra · error
Invalid state token payload
Error message
Invalid state token payload
What it means
Once the state token's signature verifies, the base64 payload is JSON-parsed into a StatePayload ({s, r, e}). If the payload is not valid base64-encoded JSON (or atob/JSON.parse throws), verifyStateToken throws 'Invalid state token payload'. This is distinct from the format and signature errors: the token looks structurally fine and authentic, but its content is unreadable.
Source
Thrown at auth/auth0/src/index.ts:138
const parts = stateToken.split('.');
if (parts.length !== 2) {
throw new Error('Invalid state token format');
}
const [payloadB64, signature] = parts as [string, string];
// Verify signature
const expectedSig = hmacSign(payloadB64, secret);
if (!timingSafeEqual(signature, expectedSig)) {
throw new Error('Invalid or tampered state token');
}
// Decode and check expiry
let payload: StatePayload;
try {
payload = JSON.parse(atob(payloadB64)) as StatePayload;
} catch {
throw new Error('Invalid state token payload');
}
if (payload.e < Date.now()) {
throw new Error('State token has expired');
}
return {
originalState: payload.s,
redirectUri: payload.r,
};
}
/**
* Simple HMAC-SHA256 using Web Crypto (sync wrapper for predictable use).
* Returns base64url-encoded signature.
*/
function hmacSign(data: string, secret: string): string {
// Use a simple hash-based approach that works synchronouslyView on GitHub (pinned to 75dd419e61)
Solutions
- Generate state tokens only via createStateToken — don't hand-assemble base64 payloads and sign them yourself.
- Ensure the state value survives the HTTP round trip unchanged (proper URL encoding of '.' and '+', no proxy rewriting).
- Handle the error as a failed login: reject the callback with a 4xx and restart the OAuth flow; the payload is unrecoverable by design.
- If you upgraded the library, invalidate in-flight sessions/tokens created by the old payload format.
- Distinguish this catch from expiry: this error means undecodable payload, while 'State token has expired' (payload.e < Date.now()) means a valid but stale token — both resolve by restarting login.
Example fix
// before
const { originalState, redirectUri } = verifyStateToken(state, secret); // throws 'Invalid state token payload'
// after
try {
var { originalState, redirectUri } = verifyStateToken(state, secret);
} catch {
return Response.redirect('/login'); // restart OAuth flow
} Defensive patterns
Strategy: try-catch
Validate before calling
function statePayloadLooksValid(v) {
if (!isStateToken(v)) return false;
try {
const [b64] = v.split('.');
const payload = JSON.parse(atob(b64));
return typeof payload.e === 'number' && typeof payload.s === 'string' && typeof payload.r === 'string';
} catch {
return false;
}
} Type guard
function isStatePayload(p: unknown): p is { s: string; r: string; e: number } {
return typeof p === 'object' && p !== null &&
typeof (p as any).s === 'string' &&
typeof (p as any).r === 'string' &&
typeof (p as any).e === 'number';
} Try / catch
try {
const { originalState, redirectUri } = verifyStateToken(state, secret);
} catch (err) {
// covers 'Invalid state token payload' and 'State token has expired'
return Response.redirect(new URL('/login', req.url));
} Prevention
- Always mint state tokens with createStateToken; never sign custom payloads.
- Check token age client-side is unnecessary — treat any payload/parse/expiry error identically by restarting login.
- Invalidate tokens from old library versions after upgrades that touch the payload schema.
- Return the user to the login flow on any state verification failure rather than surfacing a raw 500.
When it happens
Trigger: A token signed correctly but whose payload decodes to non-JSON (hand-rolled token signing someone else's payload string with hmacSign), a payload encoded with base64url or UTF-8-safe encodings incompatible with atob, or corrupted payload characters introduced in transit.
Common situations: Custom tooling or tests that sign arbitrary strings instead of using createStateToken; an intermediary that mangles the state parameter; a future/other version of the library changed the payload schema while old tokens still pass signature checks with the same secret.
Related errors
- Invalid state token format
- Invalid state token payload
- Invalid or tampered state token
- Redirect URI is required for SSO. Set AUTH0_REDIRECT_URI or
- Token exchange failed: ${error}
AI-assisted analysis of mastra-ai/mastra@75dd419e61 (2026-08-30).
Data as JSON: /api/errors/3297e36e023f1d35.
Report an issue: GitHub.