mastra-ai/mastra · warning
Invalid state token signature
Error message
Invalid state token signature
What it means
After confirming the two-part format, verifyStateToken recomputes the HMAC-SHA256 signature of the base64 payload with the provider secret and compares it with timingSafeEqual. A mismatch means the state token was forged or altered (or was signed with a different secret), so the provider rejects the OAuth callback to prevent CSRF.
Source
Thrown at auth/clerk/src/index.ts:162
}
/**
* 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.
*/
function escapeRegex(str: string): string {
return str.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
}
/**View on GitHub (pinned to 75dd419e61)
Solutions
- Ensure all server instances use the identical provider secret (same env var value) so signatures validate cluster-wide.
- Restart the OAuth flow to obtain a fresh state token signed with the current secret.
- Confirm the callback hit the same environment/tenant that initiated the flow (no cross-environment state reuse).
- If this fires for legitimate users, check for intermediaries rewriting the state query parameter.
Example fix
// before: secret differs between the instance that issued state and the one validating it
// instance A: new MastraAuthClerk({ secretKey: 'old-secret' })
// instance B: new MastraAuthClerk({ secretKey: 'new-secret' })
// after: share one secret via env across all replicas
const auth = new MastraAuthClerk({ secretKey: process.env.CLERK_AUTH_SECRET }); Defensive patterns
Strategy: try-catch
Validate before calling
if (process.env.CLERK_AUTH_SECRET === undefined || process.env.CLERK_AUTH_SECRET.length < 32) {
throw new Error('CLERK_AUTH_SECRET must be set identically on all instances before handling OAuth callbacks');
} Type guard
function isStateSignatureError(e: unknown): e is Error {
return e instanceof Error && e.message === 'Invalid state token signature';
} Try / catch
try {
const { redirectUri } = await verifyStateToken(state, secret);
} catch (e) {
if (isStateSignatureError(e)) {
// likely forged or secret mismatch across replicas; do not proceed with OAuth
return respondBadRequest('state signature mismatch — restart OAuth sign-in');
}
throw e;
} Prevention
- Deploy the identical provider secret to every replica (managed secrets, no per-instance values).
- Rotate secrets in a coordinated rollout and invalidate in-flight OAuth flows.
- Never accept state tokens across environments; treat signature failure as a potential CSRF attempt and log it.
When it happens
Trigger: verifyStateToken(stateToken, secret) where timingSafeEqual(signature, expectedSig) is false — state payload/signature tampered with, provider secret changed between flow start and callback (multi-instance deploy with different secrets/env configs), or a state minted by another environment (staging token validated in prod).
Common situations: Rotating or mismatching the Clerk provider secret across server replicas so tokens signed by instance A fail on instance B; staging-to-prod URL reuse; attackers modifying the base64 payload; expired flows replayed after the signature is recomputed with a rotated key.
Related errors
- Invalid or tampered state token
- Invalid state token signature
- Invalid state token format
- Invalid state token format
- Redirect URI is required for SSO login
AI-assisted analysis of mastra-ai/mastra@75dd419e61 (2026-08-30).
Data as JSON: /api/errors/110a05ccacdbca0e.
Report an issue: GitHub.