usememos/memos · error · Error
Failed to initialize OAuth flow
Error message
Failed to initialize OAuth flow
What it means
Thrown by initializeOAuthFlow when sessionStorage.setItem(STATE_STORAGE_KEY, ...) fails while persisting the CSRF state object before redirecting to the identity provider. sessionStorage can throw QuotaExceededError, SecurityError (cookies blocked in some iframe/Safari contexts), or be unavailable in private modes. Without stored state the OAuth callback cannot validate the redirect, so the flow aborts before leaving the page.
Source
Thrown at web/src/utils/oauth.ts:94
codeVerifier = undefined;
codeChallenge = undefined;
}
const stateData: OAuthState = {
state,
identityProviderName,
flowMode,
timestamp: Date.now(),
returnUrl,
linkingUserName,
codeVerifier, // Store for later retrieval in callback (undefined if PKCE not available)
};
try {
sessionStorage.setItem(STATE_STORAGE_KEY, JSON.stringify(stateData));
} catch (error) {
console.error("Failed to store OAuth state:", error);
throw new Error("Failed to initialize OAuth flow");
}
return { state, codeChallenge };
}
// Validate and retrieve OAuth state from storage (CSRF protection)
// Returns identityProviderName, flowMode, returnUrl, linkingUserName, and codeVerifier for PKCE
export function validateOAuthState(
stateParam: string,
): { identityProviderName: string; flowMode: OAuthFlowMode; returnUrl?: string; linkingUserName?: string; codeVerifier?: string } | null {
try {
const storedData = sessionStorage.getItem(STATE_STORAGE_KEY);
if (!storedData) {
console.error("No OAuth state found in storage");
return null;
}
const stateData: OAuthState = JSON.parse(storedData);View on GitHub (pinned to 14d757ce1f)
Solutions
- Check browser settings: allow cookies/site data for the Memos origin, and retry the sign-in.
- If embedding Memos in an iframe, add allow-same-origin to the sandbox attributes or open in a top-level tab.
- Clear the origin's sessionStorage (DevTools > Application > Session Storage) to free quota and retry.
- As a code hardening step, prune stale STATE_STORAGE_KEY entries before writing and surface the underlying caught error (currently swallowed into console.error) for diagnosability.
Example fix
// before
try {
sessionStorage.setItem(STATE_STORAGE_KEY, JSON.stringify(stateData));
} catch (error) {
console.error("Failed to store OAuth state:", error);
throw new Error("Failed to initialize OAuth flow");
}
// after (surface cause + prune stale state)
try {
sessionStorage.removeItem(STATE_STORAGE_KEY);
sessionStorage.setItem(STATE_STORAGE_KEY, JSON.stringify(stateData));
} catch (error) {
throw new Error(`Failed to initialize OAuth flow: ${error instanceof Error ? error.message : String(error)}`);
} Defensive patterns
Strategy: try-catch
Validate before calling
function sessionStorageAvailable(): boolean {
try {
const probe = "__oauth_probe__";
sessionStorage.setItem(probe, "1");
sessionStorage.removeItem(probe);
return true;
} catch {
return false;
}
}
// before starting the flow:
if (!sessionStorageAvailable()) {
showError("Enable site data/cookies to sign in with SSO.");
return;
} Type guard
function isStorageError(e: unknown): e is DOMException {
return e instanceof DOMException && (e.name === "QuotaExceededError" || e.name === "SecurityError");
} Try / catch
try {
sessionStorage.setItem(STATE_STORAGE_KEY, JSON.stringify(stateData));
} catch (error) {
if (error instanceof DOMException && error.name === "QuotaExceededError") {
sessionStorage.clear(); // or remove stale keys and retry once
}
throw new Error(`Failed to initialize OAuth flow: ${error instanceof Error ? error.message : String(error)}`);
} Prevention
- Probe sessionStorage writability before showing the SSO sign-in button.
- Prune the previous STATE_STORAGE_KEY entry before writing a new one.
- Never embed Memos in a sandboxed iframe without allow-same-origin if SSO is used.
When it happens
Trigger: Calling the OAuth init (signInWithIdp / link flow in web/src/utils/oauth.ts) when sessionStorage is full, blocked (Safari ITP / all-cookies-blocked), or accessed in a sandboxed iframe without allow-same-origin; also JSON.stringify of the state object itself cannot fail here, so the setItem call is the sole thrower.
Common situations: Browser set to block all cookies; Safari private mode; embedding Memos in an iframe; repeated large writes filling the 5MB origin quota; iOS WebView with storage partitioning.
Related errors
- Failed to link account. Please sign in to Memos again and re
- The signed-in user changed before the OAuth callback complet
AI-assisted analysis of usememos/memos@14d757ce1f (2026-08-15).
Data as JSON: /api/errors/f1e9833ea5dc030b.
Report an issue: GitHub.