mastra-ai/mastra · error
Invalid encrypted session data
Error message
Invalid encrypted session data
What it means
Google SSO session data is encrypted as base64(AES-GCM(payload)) with a leading salt (SALT_LENGTH bytes) and IV (IV_LENGTH bytes). decryptSession base64-decodes the blob and throws if the decoded buffer is shorter than salt+IV+1 bytes, because no valid ciphertext could exist — the input is truncated or not actually an encrypted session produced by this library.
Source
Thrown at auth/google/src/auth-provider.ts:130
}
async function encryptSession(data: unknown, password: string): Promise<string> {
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));
}
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));
}
async function hmacSign(data: string, secret: string): Promise<string> {
const encoder = new TextEncoder();
const cryptoKey = await crypto.subtle.importKey(
'raw',
encoder.encode(secret),
{ name: 'HMAC', hash: 'SHA-256' },
false,
['sign'],
);View on GitHub (pinned to 75dd419e61)
Solutions
- Delete/re-issue the session: redirect the user to re-authenticate so fresh session data is encrypted and stored.
- Verify the stored value is the exact output of encryptSession (base64, salt+IV prefixed), not plaintext or a JWT.
- Check cookie size limits; if the blob is near 4KB, store session server-side and keep only a small reference in the cookie.
- Confirm the same cookiePassword/encryption format is used across versions and instances (mismatched formats produce garbage or short blobs).
Example fix
// before
const session = await decryptSession(cookies.get('session') ?? '', password);
// after
const raw = cookies.get('session');
if (!raw || raw.length < 44) { // ~min salt+IV+ciphertext base64
return redirectToLogin(); // no/invalid session, re-auth instead of throwing
}
const session = await decryptSession(raw, password); Defensive patterns
Strategy: validation
Validate before calling
function looksLikeEncryptedSession(v: unknown): v is string {
if (typeof v !== 'string' || v.length === 0) return false;
try {
const bytes = Uint8Array.from(atob(v), c => c.charCodeAt(0));
return bytes.length >= 16 + 12 + 1; // SALT_LENGTH + IV_LENGTH + ciphertext
} catch {
return false;
}
}
if (!looksLikeEncryptedSession(cookieValue)) return reauthenticate(); Type guard
function isEncryptedSession(v: unknown): v is string {
return typeof v === 'string' && v.length >= 40 && /^[A-Za-z0-9+/]+=*$/.test(v);
} Prevention
- Treat an undecryptable/short session as 'no session' and re-authenticate instead of throwing.
- Watch cookie size limits (4KB) — store large sessions server-side.
- Don't store plaintext tokens or JWTs where the encrypted session blob is expected.
- Keep the cookiePassword and encryption format stable across versions/instances.
When it happens
Trigger: Calling decryptSession (or accessing the `sessionData` getter backed by it) with a string that isn't base64 of a salted+IV-prefixed AES-GCM blob — e.g. an empty string, a plaintext token, a JWT, or a value truncated by storage limits.
Common situations: Cookie truncated by the browser's ~4KB limit or by a CDN/proxy; storing plaintext session JSON instead of the encrypted form; decoding the base64 twice or passing a base64url variant with padding stripped; old sessions encrypted with a different format after a library upgrade.
Related errors
- Invalid encrypted session data
- Cookie password must be at least 32 characters for SSO. Set
- Invalid state redirect suffix
- Invalid state token format
- Invalid state token signature
AI-assisted analysis of mastra-ai/mastra@75dd419e61 (2026-08-30).
Data as JSON: /api/errors/9a3901fa884548fb.
Report an issue: GitHub.