Hi Stytch team,
I’m experiencing an issue with Microsoft SSO authentication in my React app using Stytch B2B. The problem occurs specifically after logout and attempting to log in again. When i do login with microsoft, even though all the cookies and session is cleared the slug and token are getting attached to the url
Problem:
After logging out and clicking “Login with Microsoft”, the user is immediately redirected back to the app with a valid Stytch token, bypassing the Microsoft login prompt entirely.
My logout function that clears both client session and backend session, which pass successfully :
const handleLogout = async () => {
try {
console.log('🔐 Starting logout process...', {
currentUrl: window.location.href,
hasMember: !!member,
memberId: member?.member_id
});
// 1. Revoke Stytch session on the frontend FIRST
try {
console.log("🔐 Attempting to revoke Stytch session on the frontend...");
await client.session.revoke();
console.log("✅ Stytch session revoked on the frontend.");
} catch (err) {
console.error("❌ Failed to revoke Stytch session:", err);
}
// 2. Clear backend session with member_id
const memberId = member?.member_id;
try {
console.log('🔐 Clearing backend session...', { memberId });
await fetch("http://localhost:5001/auth/logout", {
method: "POST",
headers: { "Content-Type": "application/json" },
credentials: "include",
body: JSON.stringify({ member_id: memberId }),
});
console.log('🔐 Backend session cleared successfully');
} catch (err) {
console.warn('🔐 Failed to clear backend session:', err);
}
// 3. Clear our app's state
setIsAuthenticated(false);
setMemberId(null);
setIntermediateSessionToken(null);
// 4. Clear local storage and session storage
console.log('🔐 Clearing storage...');
localStorage.clear();
sessionStorage.clear();
// 5. Redirect to login page
console.log('🔐 Redirecting to login page');
window.location.href = '/login';
} catch (err) {
console.error("🔐 Logout failed:", err);
window.location.href = '/login';
}
};
My sso and username pw + mfa flow (which could be getting in the way) :
useEffect(() => {
// Check for SSO token in URL first
const params = new URLSearchParams(window.location.search);
const token = params.get("token");
const isSSO = params.get("stytch_token_type") === "oauth";
const error = params.get("error");
// Handle OAuth errors
if (error) {
console.error("🔄 SSO Flow - OAuth error:", error);
message.error("SSO login failed. Please try again or use password login.");
// Clear URL parameters
window.history.replaceState({}, document.title, "/login");
setLoading(false);
return;
}
if (token && isSSO && !isAuthenticating) {
console.log("🔄 SSO Flow - Starting SSO authentication...", { currentUrl: window.location.href });
setIsAuthenticating(true);
setLoading(true);
const handleSSOCallback = async () => {
try {
const result = await stytchClient.oauth.authenticate({
oauth_token: token,
session_duration_minutes: 60,
});
// Log state, storage, and cookies AFTER successful SSO login
console.log('=== AFTER LOGIN ===');
console.log('Auth state:', {
isAuthenticated: true,
memberId: result.member?.member_id,
intermediateSessionToken: result.intermediate_session_token
});
console.log('localStorage:', {...localStorage});
console.log('sessionStorage:', {...sessionStorage});
console.log('document.cookie:', document.cookie);
// Store intermediate session token in localStorage
if (result.intermediate_session_token) {
localStorage.setItem('intermediate_session_token', result.intermediate_session_token);
}
// Clear the URL parameters before setting auth state
window.history.replaceState({}, document.title, "/");
console.log("🔄 SSO Flow - URL parameters cleared", { newUrl: window.location.href });
// Set auth state
setIsAuthenticated(true);
setAuthMemberId(result.member?.member_id || null);
setIntermediateSessionToken(result.intermediate_session_token || null);
console.log("🔄 SSO Flow - Auth state updated, navigating to home", { currentUrl: window.location.href });
navigate("/", { replace: true });
} catch (err) {
console.error("🔄 SSO Flow - Authentication failed:", {
error: err,
currentUrl: window.location.href
});
setIsAuthenticated(false);
// Clear all URL parameters on error
window.history.replaceState({}, document.title, "/login");
navigate("/login", { replace: true });
} finally {
setLoading(false);
setIsAuthenticating(false);
}
};
handleSSOCallback();
} else if (!token && !isAuthenticated) {
console.log("🔄 SSO Flow - No SSO token and not authenticated, showing login form", {
currentUrl: window.location.href,
searchParams: Object.fromEntries(params.entries())
});
// Clear any leftover URL parameters
if (window.location.search) {
window.history.replaceState({}, document.title, "/login");
}
setLoading(false);
}
}, [navigate, setIsAuthenticated, setAuthMemberId, setIntermediateSessionToken, stytchClient.oauth, isAuthenticating, isAuthenticated]);
const handlePasswordLogin = async () => {
try {
console.log("🔑 Password Login - Starting...", { currentUrl: window.location.href });
// Clear any SSO session marker since this is password login
localStorage.removeItem('sso_session');
const result = await stytchClient.passwords.authenticate({
organization_id: organizationId,
email_address: email,
password,
session_duration_minutes: 60,
});
const memberId = result.member?.member_id;
const isMfaEnrolled = result.member?.mfa_enrolled;
const intermediateSessionToken = result.intermediate_session_token;
const mfaRequired = result.mfa_required;
console.log("🔑 Password Login - Auth result:", {
isMfaEnrolled,
mfaRequired,
hasIntermediateToken: !!intermediateSessionToken
});
// Store intermediate session token in localStorage
if (intermediateSessionToken) {
localStorage.setItem('intermediate_session_token', intermediateSessionToken);
}
setIntermediateSession(intermediateSessionToken || '');
setMemberId(memberId || '');
setAuthMemberId(memberId || '');
setIntermediateSessionToken(intermediateSessionToken || '');
if (isMfaEnrolled) {
console.log("🔑 Password Login - MFA verification required", { currentUrl: window.location.href });
setShowMFA(true);
} else if (mfaRequired) {
console.log("🔑 Password Login - MFA setup required", { currentUrl: window.location.href });
navigate("/totp-setup", {
state: {
memberId,
intermediateSessionToken,
},
});
} else {
console.log("🔑 Password Login - No MFA required, proceeding to home", { currentUrl: window.location.href });
setIsAuthenticated(true);
navigate("/");
}
} catch (error) {
console.error("🔑 Password Login - Failed:", {
error,
currentUrl: window.location.href
});
message.error("Failed to login. Please try again.");
}
};