mastra-ai/mastra · error
Invalid state token signature
Error message
Invalid state token signature
What it means
After confirming the `payload.signature` shape, verifyStateToken recomputes an HMAC over the base64 payload with the provider's secret and compares it to the attached signature using a timing-safe equality. A mismatch means the payload was altered, the signature is from a different secret, or the token was forged/copied from another environment — so verification fails closed.
Source
Thrown at auth/google/src/auth-provider.ts:195
};
const payloadB64 = btoa(JSON.stringify(payload));
const signature = await hmacSign(payloadB64, secret);
return `${payloadB64}.${signature}`;
}
async function verifyStateToken(
stateToken: string,
secret: string,
): Promise<{ originalState: string; redirectUri: string; nonce: string }> {
const parts = stateToken.split('.');
if (parts.length !== 2) {
throw new Error('Invalid state token format');
}
const [payloadB64, signature] = parts as [string, string];
const expectedSig = await hmacSign(payloadB64, secret);
if (!timingSafeEqual(signature, expectedSig)) {
throw new Error('Invalid state token signature');
}
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,
nonce: payload.n,
};View on GitHub (pinned to 75dd419e61)
Solutions
- Ensure the exact same secret (env var / provider options) is deployed to every instance that can serve the OAuth callback.
- If secrets were recently rotated, have affected users restart login — previously issued state tokens can't verify against the new secret.
- Restart the flow to get a fresh state token if the error is one-off (rules out transient tampering).
- Check that no middleware re-encodes the state (base64url vs base64, padding) between issuance and verification.
Example fix
// before
const provider = new GoogleAuthProvider({ /* secret pulled from per-instance config */ });
// after: pin one secret everywhere
const secret = process.env.OAUTH_STATE_SECRET;
if (!secret) throw new Error('OAUTH_STATE_SECRET must be set identically on all replicas');
const provider = new GoogleAuthProvider({ stateSecret: secret }); Defensive patterns
Strategy: try-catch
Try / catch
try {
await verifyStateToken(state, secret);
} catch (e) {
if ((e as Error).message === 'Invalid state token signature') {
logger.warn('State signature mismatch — check secret consistency across replicas or secret rotation');
return restartLoginFlow();
}
throw e;
} Prevention
- Deploy an identical state secret to every replica that can serve the callback (shared secret manager).
- Invalidate/drain in-flight logins around secret rotations; expect re-login.
- Keep proxies from re-encoding the base64 payload between issue and verify.
- Treat signature failures as potential tampering — log and restart the flow, never bypass.
When it happens
Trigger: verifyStateToken computes `expectedSig = hmacSign(payloadB64, secret)` and `timingSafeEqual(signature, expectedSig)` returns false during Google SSO callback verification.
Common situations: Different CLERK/Google provider secret (or cookiePassword-derived secret) between the instance that issued the token and the instance verifying it — e.g. multiple server replicas with diverging env vars, or rotating secrets without invalidating in-flight logins; payload tampering; state token copied from a dev environment into prod; base64 re-encoding by a proxy altering the signed bytes.
Related errors
- Invalid or tampered state token
- Invalid state token signature
- Invalid state redirect suffix
- Invalid state token format
- Google service account token request failed (${response.stat
AI-assisted analysis of mastra-ai/mastra@75dd419e61 (2026-08-30).
Data as JSON: /api/errors/c3b1a80f6702faba.
Report an issue: GitHub.