mastra-ai/mastra · error

Invalid or tampered state token

Error message

Invalid or tampered state token

What it means

After splitting the state token, verifyStateToken recomputes the HMAC-SHA256 signature of the payload with the server secret and compares it to the signature in the token using a timing-safe comparison. If they differ, the payload was modified, was signed with a different secret, or is not from this server — so it throws 'Invalid or tampered state token' to prevent CSRF and open-redirect via a forged redirectUri.

Source

Thrown at auth/auth0/src/index.ts:130

  return `${payloadB64}.${signature}`;
}

/**
 * Verify and decode a state token.
 * Returns the original state and redirectUri if valid and not expired.
 */
function verifyStateToken(stateToken: string, secret: string): { originalState: string; redirectUri: string } {
  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,
  };

View on GitHub (pinned to 75dd419e61)

Solutions

  1. Ensure the same signing secret is configured on both the login endpoint and the callback endpoint (same env var, same value) and was not rotated mid-flow.
  2. Confirm multi-instance/multi-region deployments share the secret via the same secret store.
  3. Restart the login flow — a mismatched or expired token can never be verified; the user must begin a new OAuth authorize redirect.
  4. If this fires unexpectedly in production, audit for token tampering (potential CSRF) and log the event server-side without trusting the payload.
  5. Do not weaken or bypass the timing-safe comparison; verify against the exact payload string received.

Example fix

// before
const token = verifyStateToken(state, process.env.AUTH0_SECRET ?? 'dev-secret');
// after
const secret = process.env.AUTH0_SECRET;
if (!secret) throw new Error('AUTH0_SECRET not configured');
const token = verifyStateToken(state, secret);
Defensive patterns

Strategy: try-catch

Validate before calling

// No caller-side check can verify HMAC; instead ensure secret parity before the flow:
if (!process.env.AUTH0_SECRET) {
  throw new Error('Refusing to run OAuth flow: AUTH0_SECRET is not set');
}

Try / catch

try {
  const { originalState, redirectUri } = verifyStateToken(state, secret);
} catch (err) {
  if (err instanceof Error && err.message === 'Invalid or tampered state token') {
    log.warn('OAuth state signature mismatch — possible CSRF or secret rotation', { hasState: !!state });
    return new Response('Invalid OAuth state', { status: 400 });
  }
  throw err;
}

Prevention

When it happens

Trigger: Calling verifyStateToken with a token whose signature part doesn't match hmacSign(payloadB64, secret): hand-edited payload, token generated with a different/rotated secret, or a token copied from another environment (staging token verified in production).

Common situations: SESSION/AUTH secret differs between environments or changed between the login redirect and callback (deploy, secret rotation, missing env var falling back to a default); multi-instance deployments without a shared secret; an attacker-supplied state in a CSRF attempt (this error is the protection working).

Related errors


AI-assisted analysis of mastra-ai/mastra@75dd419e61 (2026-08-30). Data as JSON: /api/errors/556615bb6b7afcc5. Report an issue: GitHub.