mastra-ai/mastra · error

Invalid encrypted session data

Error message

Invalid encrypted session data

What it means

Auth0 session cookies are encrypted with AES-GCM and serialized as base64(salt || iv || ciphertext). decryptSession first base64-decodes the cookie and checks the byte length is at least 16 (salt) + 12 (iv) + 1 (some ciphertext). If the decoded blob is too short to even contain the salt and IV, the library throws 'Invalid encrypted session data' rather than attempting a doomed decryption.

Source

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

  const encoder = new TextEncoder();
  const salt = crypto.getRandomValues(new Uint8Array(SALT_LENGTH));
  const key = await deriveKey(password, salt, 'encrypt');
  const iv = crypto.getRandomValues(new Uint8Array(IV_LENGTH));
  const encrypted = await crypto.subtle.encrypt({ name: 'AES-GCM', iv }, key, encoder.encode(JSON.stringify(data)));
  const combined = new Uint8Array(salt.length + iv.length + new Uint8Array(encrypted).length);
  combined.set(salt);
  combined.set(iv, salt.length);
  combined.set(new Uint8Array(encrypted), salt.length + iv.length);
  return btoa(String.fromCharCode(...combined));
}

/**
 * Decrypt session data from cookie.
 */
async function decryptSession(encrypted: string, password: string): Promise<unknown> {
  const combined = Uint8Array.from(atob(encrypted), c => c.charCodeAt(0));
  if (combined.length < SALT_LENGTH + IV_LENGTH + 1) {
    throw new Error('Invalid encrypted session data');
  }
  const salt = combined.slice(0, SALT_LENGTH);
  const iv = combined.slice(SALT_LENGTH, SALT_LENGTH + IV_LENGTH);
  const data = combined.slice(SALT_LENGTH + IV_LENGTH);
  const key = await deriveKey(password, salt, 'decrypt');
  const decrypted = await crypto.subtle.decrypt({ name: 'AES-GCM', iv }, key, data);
  return JSON.parse(new TextDecoder().decode(decrypted));
}

/** OAuth state token expiry (10 minutes) */
const STATE_TOKEN_EXPIRY_MS = 10 * 60 * 1000;

interface StatePayload {
  /** Original state from caller */
  s: string;
  /** Redirect URI */
  r: string;
  /** Expiry timestamp */

View on GitHub (pinned to 75dd419e61)

Solutions

  1. Delete the invalid auth0_session cookie on the client and force a fresh login — corrupted/foreign cookies cannot be repaired.
  2. Confirm the cookie value comes from encryptSession of this library version (base64 salt||iv||ciphertext); invalidate cookies from older formats after upgrades.
  3. Check that no middleware/proxy rewrites or truncates Set-Cookie headers and that no other app on the domain writes the same cookie name.
  4. Verify the session password secret is configured; note a wrong password throws later at AES-GCM decryption, while this error means the blob shape itself is wrong.
  5. Wrap session decryption in try/catch and treat failure as 'no session' (redirect to login) instead of a 500.

Example fix

// before
const session = await decryptSession(req.cookies['auth0_session'], secret);
// after
let session = null;
try {
  session = await decryptSession(req.cookies['auth0_session'], secret);
} catch {
  session = null; // treat as logged out, redirect to /login
}
Defensive patterns

Strategy: try-catch

Validate before calling

function looksLikeEncryptedSession(v) {
  if (typeof v !== 'string' || v.length === 0) return false;
  try {
    return atob(v).length >= 16 + 12 + 1;
  } catch {
    return false;
  }
}
const hasSession = looksLikeEncryptedSession(req.cookies['auth0_session']);

Type guard

function isEncryptedSessionBlob(v: unknown): v is string {
  if (typeof v !== 'string') return false;
  try { return atob(v).length >= 29; } catch { return false; }
}

Try / catch

let session: Session | null = null;
try {
  session = await provider.sessionData(req);
} catch (err) {
  if (err instanceof Error && err.message === 'Invalid encrypted session data') {
    session = null; // clear cookie & redirect to login
    res.setHeader('Set-Cookie', 'auth0_session=; Max-Age=0; Path=/');
  } else throw err;
}

Prevention

When it happens

Trigger: Calling decryptSession (via sessionData) with a value that is not valid base64 (atob throws), or whose decoded length is under 29 bytes — e.g. an empty, truncated, or plaintext (non-encrypted) cookie value.

Common situations: Cookie was cleared/truncated by the browser or a proxy; an old cookie from a previous encryption format survived a library upgrade; a session cookie name collides with another app on the same domain; someone sends a forged or garbage cookie value; deploying without the same session password so you rotate formats manually.

Related errors


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