mastra-ai/mastra · warning
Invalid state token format
Error message
Invalid state token format
What it means
Clerk OAuth state tokens in this provider are signed strings of the form `<payloadB64>.<hmacSignature>`; verifyStateToken splits on '.' and requires exactly two parts before verifying the HMAC. A token not matching `payload.signature` means it was corrupted, truncated, hand-crafted, or was never issued by this provider's createStateToken.
Source
Thrown at auth/clerk/src/index.ts:156
r: redirectUri,
e: Date.now() + STATE_TOKEN_EXPIRY_MS,
};
const payloadB64 = btoa(JSON.stringify(payload));
const signature = await hmacSign(payloadB64, secret);
return `${payloadB64}.${signature}`;
}
/**
* Verify and decode a state token.
* Returns the original state and redirectUri if valid and not expired.
*/
async function verifyStateToken(
stateToken: string,
secret: string,
): Promise<{ originalState: string; redirectUri: string }> {
const parts = stateToken.split('.');
if (parts.length !== 2) {
throw new Error('Invalid state token format');
}
const [payloadB64, signature] = parts;
const expectedSig = await hmacSign(payloadB64!, secret);
if (!timingSafeEqual(signature!, expectedSig)) {
throw new Error('Invalid state token signature');
}
const payload = JSON.parse(atob(payloadB64!)) as StatePayload;
if (payload.e < Date.now()) {
throw new Error('State token has expired');
}
return { originalState: payload.s, redirectUri: payload.r };
}
/**
* Escape special regex characters in a string.View on GitHub (pinned to 75dd419e61)
Solutions
- Restart the OAuth flow: generate a fresh state via the provider's redirect flow and use it unmodified in the callback.
- Ensure the state query parameter is passed through URL encoding unchanged — do not decode/re-encode or append query params to it.
- Verify the same state is round-tripped: the callback URL used by Clerk must be the one generated by the provider.
Example fix
// before: manually rebuilding the callback URL and dropping part of state
const url = `/auth/callback?state=${state.split('.')[0]}`;
// after: pass state through verbatim
const url = `/auth/callback?state=${encodeURIComponent(state)}`; Defensive patterns
Strategy: try-catch
Validate before calling
const state = new URL(callbackUrl).searchParams.get('state');
if (!state || state.split('.').length !== 2) {
return respondBadRequest('state parameter is malformed; restart the OAuth flow');
} Type guard
function isWellFormedStateToken(state: string | null | undefined): state is string {
return typeof state === 'string' && /^[A-Za-z0-9+/=_-]+\.[A-Za-z0-9+/=_-]+$/.test(state);
} Try / catch
try {
const { redirectUri } = await verifyStateToken(state, secret);
} catch (e) {
if (e instanceof Error && e.message === 'Invalid state token format') {
return respondBadRequest('state mismatch — restart OAuth sign-in');
}
throw e;
} Prevention
- Pass the state query parameter through verbatim; never parse, trim, or rebuild it.
- Restart the OAuth flow whenever state validation fails instead of retrying the stale callback.
- Ensure proxies don't rewrite query strings on the OAuth callback route.
When it happens
Trigger: verifyStateToken(stateToken, secret) where stateToken.split('.').length !== 2 — callback query param ?state= missing its signature part, double-encoding mangling the dot, or an attacker/random string supplied as state in the OAuth redirect callback.
Common situations: Reverse proxies or frameworks re-encoding the state query parameter; client-side code trimming/altering the state value; an attacker probing the OAuth callback endpoint (this check correctly rejects them); copying a state from a different environment.
Related errors
- Invalid state token signature
- Invalid state token format
- Invalid or tampered state token
- Redirect URI is required for SSO login
- Token exchange failed: ${error}
AI-assisted analysis of mastra-ai/mastra@75dd419e61 (2026-08-30).
Data as JSON: /api/errors/56637e77612e6a61.
Report an issue: GitHub.