usememos/memos · warning · Error
The signed-in user changed before the OAuth callback complet
Error message
The signed-in user changed before the OAuth callback completed. Please retry linking from account settings.
What it means
Thrown in AuthCallback when the stored OAuth link state carries linkingUserName but the currently signed-in Memos user (currentUser.name) differs at callback time. It prevents attaching the IdP identity to the wrong account when the active session changed during the IdP round-trip (e.g., user signed out and back in as someone else in another tab).
Source
Thrown at web/src/pages/AuthCallback.tsx:90
setState({
loading: false,
errorMessage: "Failed to authorize. Invalid or expired state parameter. This may indicate a CSRF attack attempt.",
});
return;
}
const { flowMode, identityProviderName, returnUrl, linkingUserName, codeVerifier } = validatedState;
const redirectUri = absolutifyLink("/auth/callback");
handledRef.current = true;
(async () => {
try {
if (flowMode === "link") {
if (!currentUser?.name) {
throw new Error("Failed to link account. Please sign in to Memos again and retry.");
}
if (linkingUserName && currentUser.name !== linkingUserName) {
throw new Error("The signed-in user changed before the OAuth callback completed. Please retry linking from account settings.");
}
await userServiceClient.createLinkedIdentity({
parent: currentUser.name,
idpName: identityProviderName,
code,
redirectUri,
codeVerifier: codeVerifier || "",
});
} else {
const response = await authServiceClient.signIn({
credentials: {
case: "ssoCredentials",
value: {
idpName: identityProviderName,
code,
redirectUri,
codeVerifier: codeVerifier || "", // Pass PKCE code_verifier for token exchange
},View on GitHub (pinned to 14d757ce1f)
Solutions
- Retry the linking flow from the account settings of the user you actually want to link, staying signed in as that user for the whole round-trip.
- Close other Memos tabs before starting a link to avoid cross-tab user switches.
- Sign out fully, sign in as the intended user, then link.
- No code change needed — this is a deliberate safety abort; the identity has not been linked.
Defensive patterns
Strategy: validation
Validate before calling
// at callback, before calling createLinkedIdentity
if (linkingUserName && currentUser?.name && currentUser.name !== linkingUserName) {
showError(`Signed in as ${currentUser.name}, but the link was started by ${linkingUserName}. Retry from settings.`);
return;
} Try / catch
catch (e) {
if (e instanceof Error && e.message.startsWith("The signed-in user changed")) {
// safe no-op: identity was NOT linked; prompt retry
navigate("/settings", { state: { relink: identityProviderName } });
}
} Prevention
- Do not switch Memos accounts in other tabs while a link flow is in flight.
- Sign out and back in as the intended user, then restart linking.
- Treat this error as a guardrail: never bypass it by stripping the linkingUserName check.
When it happens
Trigger: Start link as user A, then before the IdP redirect returns, sign out and sign in as user B (same browser) via BroadcastChannel-synced auth state; callback now sees currentUser.name !== linkingUserName and aborts createLinkedIdentity.
Common situations: Multi-account admins testing linking; sign-out in another tab mid-flow; dev environments where switching users between keycloak redirects is routine; stale tab completing an old link attempt after a user switch.
Related errors
- Failed to link account. Please sign in to Memos again and re
- Failed to initialize OAuth flow
- internal IP addresses are not allowed
- only http/https protocols are allowed
AI-assisted analysis of usememos/memos@14d757ce1f (2026-08-15).
Data as JSON: /api/errors/5ac845d7cff6197a.
Report an issue: GitHub.