mastra-ai/mastra · error

State parameter has expired

Error message

State parameter has expired

What it means

Thrown by handleCallback when the stored state entry exists but its expiresAt timestamp has passed. The state parameter carries a TTL to prevent replay of stale authorization redirects; expired states are rejected even if still present in the store.

Source

Thrown at auth/okta/src/auth-provider.ts:419

    });

    return `${this.endpointBase}/v1/authorize?${params.toString()}`;
  }

  /**
   * Handle the OAuth callback from Okta.
   * Note: The server passes only the stateId (UUID part), not the full state.
   */
  async handleCallback(code: string, stateId: string): Promise<SSOCallbackResult<OktaUser>> {
    // Validate state parameter (server passes only the UUID part)
    const stored = stateStore.get(stateId);
    if (!stored) {
      throw new Error('Invalid or expired state parameter');
    }
    stateStore.delete(stateId);

    if (stored.expiresAt < Date.now()) {
      throw new Error('State parameter has expired');
    }

    // Exchange code for tokens using client_secret (confidential client)
    const tokenResponse = await fetch(`${this.endpointBase}/v1/token`, {
      method: 'POST',
      headers: {
        'Content-Type': 'application/x-www-form-urlencoded',
        Authorization: `Basic ${btoa(`${this.clientId}:${this.clientSecret}`)}`,
      },
      body: new URLSearchParams({
        grant_type: 'authorization_code',
        code,
        redirect_uri: stored.redirectUri,
      }),
    });

    if (!tokenResponse.ok) {
      const error = await tokenResponse.text();

View on GitHub (pinned to 75dd419e61)

Solutions

  1. Redirect the user to restart the SSO flow to mint a fresh state.
  2. Increase the state TTL if legitimate slow logins are common (library configuration/defaults permitting).
  3. Prompt users to complete login promptly after being redirected to Okta.
  4. Check server clock correctness (NTP) if expiration seems premature.
Defensive patterns

Strategy: try-catch

Try / catch

try {
  await provider.handleCallback(code, stateId);
} catch (e) {
  if (e instanceof Error && e.message === 'State parameter has expired') {
    // redirect to a 'session expired, please sign in again' page / re-run authorize
  } else throw e;
}

Prevention

When it happens

Trigger: Calling handleCallback(code, stateId) after the state TTL elapsed — e.g. the user sat on the IdP login page too long, the callback was delayed by network issues, or a saved bookmarked callback URL is opened much later.

Common situations: User leaves the Okta login tab open for a long time before completing sign-in; slow email-link based flows; clock skew between servers in unusual setups; user resumes an abandoned login session.

Related errors


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