{"record":{"id":"d1e537ca2d030102","repo":"mastra-ai/mastra","slug":"invalid-encrypted-session-data","errorCode":null,"errorMessage":"Invalid encrypted session data","messagePattern":"Invalid encrypted session data","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"auth/auth0/src/index.ts","lineNumber":75,"sourceCode":"  const encoder = new TextEncoder();\n  const salt = crypto.getRandomValues(new Uint8Array(SALT_LENGTH));\n  const key = await deriveKey(password, salt, 'encrypt');\n  const iv = crypto.getRandomValues(new Uint8Array(IV_LENGTH));\n  const encrypted = await crypto.subtle.encrypt({ name: 'AES-GCM', iv }, key, encoder.encode(JSON.stringify(data)));\n  const combined = new Uint8Array(salt.length + iv.length + new Uint8Array(encrypted).length);\n  combined.set(salt);\n  combined.set(iv, salt.length);\n  combined.set(new Uint8Array(encrypted), salt.length + iv.length);\n  return btoa(String.fromCharCode(...combined));\n}\n\n/**\n * Decrypt session data from cookie.\n */\nasync function decryptSession(encrypted: string, password: string): Promise<unknown> {\n  const combined = Uint8Array.from(atob(encrypted), c => c.charCodeAt(0));\n  if (combined.length < SALT_LENGTH + IV_LENGTH + 1) {\n    throw new Error('Invalid encrypted session data');\n  }\n  const salt = combined.slice(0, SALT_LENGTH);\n  const iv = combined.slice(SALT_LENGTH, SALT_LENGTH + IV_LENGTH);\n  const data = combined.slice(SALT_LENGTH + IV_LENGTH);\n  const key = await deriveKey(password, salt, 'decrypt');\n  const decrypted = await crypto.subtle.decrypt({ name: 'AES-GCM', iv }, key, data);\n  return JSON.parse(new TextDecoder().decode(decrypted));\n}\n\n/** OAuth state token expiry (10 minutes) */\nconst STATE_TOKEN_EXPIRY_MS = 10 * 60 * 1000;\n\ninterface StatePayload {\n  /** Original state from caller */\n  s: string;\n  /** Redirect URI */\n  r: string;\n  /** Expiry timestamp */","sourceCodeStart":57,"sourceCodeEnd":93,"githubUrl":"https://github.com/mastra-ai/mastra/blob/75dd419e613fe9c39f846ffc500716141b74fda6/auth/auth0/src/index.ts#L57-L93","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","solutions":["Delete the invalid auth0_session cookie on the client and force a fresh login — corrupted/foreign cookies cannot be repaired.","Confirm the cookie value comes from encryptSession of this library version (base64 salt||iv||ciphertext); invalidate cookies from older formats after upgrades.","Check that no middleware/proxy rewrites or truncates Set-Cookie headers and that no other app on the domain writes the same cookie name.","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.","Wrap session decryption in try/catch and treat failure as 'no session' (redirect to login) instead of a 500."],"exampleFix":"// before\nconst session = await decryptSession(req.cookies['auth0_session'], secret);\n// after\nlet session = null;\ntry {\n  session = await decryptSession(req.cookies['auth0_session'], secret);\n} catch {\n  session = null; // treat as logged out, redirect to /login\n}","handlingStrategy":"try-catch","validationCode":"function looksLikeEncryptedSession(v) {\n  if (typeof v !== 'string' || v.length === 0) return false;\n  try {\n    return atob(v).length >= 16 + 12 + 1;\n  } catch {\n    return false;\n  }\n}\nconst hasSession = looksLikeEncryptedSession(req.cookies['auth0_session']);","typeGuard":"function isEncryptedSessionBlob(v: unknown): v is string {\n  if (typeof v !== 'string') return false;\n  try { return atob(v).length >= 29; } catch { return false; }\n}","tryCatchPattern":"let session: Session | null = null;\ntry {\n  session = await provider.sessionData(req);\n} catch (err) {\n  if (err instanceof Error && err.message === 'Invalid encrypted session data') {\n    session = null; // clear cookie & redirect to login\n    res.setHeader('Set-Cookie', 'auth0_session=; Max-Age=0; Path=/');\n  } else throw err;\n}","preventionTips":["Treat any decryption failure as 'not logged in' — always wrap session reads in try/catch and redirect to login.","Bump the cookie name (or embed a format version) when changing encryption so stale cookies are ignored after upgrades.","Avoid sharing one cookie name across multiple apps on the same domain.","Check proxies/load balancers don't truncate Set-Cookie values."],"tags":["auth0","session","encryption","cookie","validation"],"backgroundTag":"invalid-encrypted-session-cookie","analyzedSha":"75dd419e613fe9c39f846ffc500716141b74fda6","analyzedAt":"2026-08-30T00:15:31.844Z","schemaVersion":2},"datasetVersion":"2026-08-30T03:17:51.788Z"}