{"record":{"id":"c3b1a80f6702faba","repo":"mastra-ai/mastra","slug":"invalid-state-token-signature-c3b1a8","errorCode":null,"errorMessage":"Invalid state token signature","messagePattern":"Invalid state token signature","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"auth/google/src/auth-provider.ts","lineNumber":195,"sourceCode":"  };\n  const payloadB64 = btoa(JSON.stringify(payload));\n  const signature = await hmacSign(payloadB64, secret);\n  return `${payloadB64}.${signature}`;\n}\n\nasync function verifyStateToken(\n  stateToken: string,\n  secret: string,\n): Promise<{ originalState: string; redirectUri: string; nonce: string }> {\n  const parts = stateToken.split('.');\n  if (parts.length !== 2) {\n    throw new Error('Invalid state token format');\n  }\n\n  const [payloadB64, signature] = parts as [string, string];\n  const expectedSig = await hmacSign(payloadB64, secret);\n  if (!timingSafeEqual(signature, expectedSig)) {\n    throw new Error('Invalid state token signature');\n  }\n\n  let payload: StatePayload;\n  try {\n    payload = JSON.parse(atob(payloadB64)) as StatePayload;\n  } catch {\n    throw new Error('Invalid state token payload');\n  }\n\n  if (payload.e < Date.now()) {\n    throw new Error('State token has expired');\n  }\n\n  return {\n    originalState: payload.s,\n    redirectUri: payload.r,\n    nonce: payload.n,\n  };","sourceCodeStart":177,"sourceCodeEnd":213,"githubUrl":"https://github.com/mastra-ai/mastra/blob/75dd419e613fe9c39f846ffc500716141b74fda6/auth/google/src/auth-provider.ts#L177-L213","documentation":"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.","triggerScenarios":"verifyStateToken computes `expectedSig = hmacSign(payloadB64, secret)` and `timingSafeEqual(signature, expectedSig)` returns false during Google SSO callback verification.","commonSituations":"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.","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."],"exampleFix":"// before\nconst provider = new GoogleAuthProvider({ /* secret pulled from per-instance config */ });\n// after: pin one secret everywhere\nconst secret = process.env.OAUTH_STATE_SECRET;\nif (!secret) throw new Error('OAUTH_STATE_SECRET must be set identically on all replicas');\nconst provider = new GoogleAuthProvider({ stateSecret: secret });","handlingStrategy":"try-catch","validationCode":null,"typeGuard":null,"tryCatchPattern":"try {\n  await verifyStateToken(state, secret);\n} catch (e) {\n  if ((e as Error).message === 'Invalid state token signature') {\n    logger.warn('State signature mismatch — check secret consistency across replicas or secret rotation');\n    return restartLoginFlow();\n  }\n  throw e;\n}","preventionTips":["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."],"tags":["auth","google","oauth","hmac","signature-verification","csrf"],"backgroundTag":"signature-verification-failed","analyzedSha":"75dd419e613fe9c39f846ffc500716141b74fda6","analyzedAt":"2026-08-30T00:15:31.844Z","schemaVersion":2},"datasetVersion":"2026-08-30T08:17:16.595Z"}