Switch to loginRedirect — popup blocked by server COOP header
Server-level COOP prevents parent from monitoring popup.location, so loginPopup never resolves in parent. Redirect flow is the correct solution: page navigates to Microsoft, returns with #code, and handleRedirectPromise exchanges the idToken with backend. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
parent
3943be1c51
commit
2c6505f472
3 changed files with 39 additions and 35 deletions
|
|
@ -35,6 +35,35 @@ export function AuthProvider({ children }: { children: ReactNode }) {
|
|||
const navigate = useNavigate();
|
||||
const { instance, accounts, inProgress } = useMsal();
|
||||
|
||||
// Handle Microsoft redirect response on page load (loginRedirect flow)
|
||||
useEffect(() => {
|
||||
instance.handleRedirectPromise()
|
||||
.then(async (response) => {
|
||||
if (response?.idToken) {
|
||||
try {
|
||||
const backendResponse = await authApi.loginWithMicrosoft(response.idToken);
|
||||
if (backendResponse.data.access_token) {
|
||||
localStorage.setItem('auth_token', backendResponse.data.access_token);
|
||||
localStorage.setItem('user', JSON.stringify(backendResponse.data.user));
|
||||
localStorage.setItem('auth_type', 'microsoft');
|
||||
setToken(backendResponse.data.access_token);
|
||||
setUser(backendResponse.data.user);
|
||||
toast.success('Successfully signed in with Microsoft!');
|
||||
}
|
||||
} catch (err: any) {
|
||||
console.error('Backend Microsoft auth failed:', err);
|
||||
toast.error('Microsoft sign-in failed', { description: err.message });
|
||||
}
|
||||
}
|
||||
})
|
||||
.catch((err: any) => {
|
||||
if (err?.errorCode !== 'no_account_error') {
|
||||
console.error('MSAL redirect error:', err);
|
||||
toast.error('Microsoft sign-in failed', { description: err.message });
|
||||
}
|
||||
});
|
||||
}, [instance]);
|
||||
|
||||
// Listen for authentication errors and handle navigation
|
||||
useEffect(() => {
|
||||
const handleAuthError = (event: Event) => {
|
||||
|
|
@ -211,32 +240,14 @@ export function AuthProvider({ children }: { children: ReactNode }) {
|
|||
const loginWithMicrosoft = async () => {
|
||||
setIsMsalLoading(true);
|
||||
try {
|
||||
import.meta.env.DEV && console.log('Starting Microsoft authentication...');
|
||||
const response = await instance.loginPopup(loginRequest);
|
||||
|
||||
if (response && response.account && response.idToken) {
|
||||
const backendResponse = await authApi.loginWithMicrosoft(response.idToken);
|
||||
|
||||
if (backendResponse.data.access_token) {
|
||||
localStorage.setItem('auth_token', backendResponse.data.access_token);
|
||||
localStorage.setItem('user', JSON.stringify(backendResponse.data.user));
|
||||
localStorage.setItem('auth_type', 'microsoft');
|
||||
setToken(backendResponse.data.access_token);
|
||||
setUser(backendResponse.data.user);
|
||||
toast.success('Successfully signed in with Microsoft!');
|
||||
}
|
||||
}
|
||||
import.meta.env.DEV && console.log('Starting Microsoft authentication (redirect)...');
|
||||
await instance.loginRedirect(loginRequest);
|
||||
// Page navigates away — execution stops here
|
||||
} catch (error: any) {
|
||||
console.error('Microsoft login failed:', error);
|
||||
if (error.errorCode === 'popup_window_error' || error.errorCode === 'user_cancelled') {
|
||||
toast.error('Sign-in cancelled', { description: 'The sign-in window was closed.' });
|
||||
} else {
|
||||
toast.error('Microsoft sign-in failed', {
|
||||
description: error.message || 'An error occurred during authentication',
|
||||
});
|
||||
}
|
||||
throw error;
|
||||
} finally {
|
||||
console.error('Microsoft login redirect failed:', error);
|
||||
toast.error('Microsoft sign-in failed', {
|
||||
description: error.message || 'An error occurred during authentication',
|
||||
});
|
||||
setIsMsalLoading(false);
|
||||
}
|
||||
};
|
||||
|
|
@ -250,7 +261,7 @@ export function AuthProvider({ children }: { children: ReactNode }) {
|
|||
// If user was authenticated with Microsoft, also sign out from Microsoft
|
||||
if (authType === 'microsoft' && accounts.length > 0) {
|
||||
try {
|
||||
await instance.logoutPopup({
|
||||
await instance.logoutRedirect({
|
||||
account: accounts[0],
|
||||
postLogoutRedirectUri: window.location.origin + import.meta.env.BASE_URL,
|
||||
});
|
||||
|
|
|
|||
|
|
@ -2,9 +2,4 @@ import { createRoot } from 'react-dom/client'
|
|||
import App from './App.tsx'
|
||||
import './index.css'
|
||||
|
||||
// If loaded inside an MSAL popup, don't render the app.
|
||||
// The parent window's MSAL instance polls the popup URL for the auth code
|
||||
// and processes it — no React needed here.
|
||||
if (window.opener === null || window.opener === window) {
|
||||
createRoot(document.getElementById("root")!).render(<App />);
|
||||
}
|
||||
createRoot(document.getElementById("root")!).render(<App />);
|
||||
|
|
|
|||
|
|
@ -76,10 +76,8 @@ export default function Login() {
|
|||
async function handleMicrosoftLogin() {
|
||||
try {
|
||||
await loginWithMicrosoft();
|
||||
console.log('Microsoft login successful, navigating to:', from);
|
||||
navigate(from, { replace: true });
|
||||
// loginRedirect navigates the page away — no navigate() call needed
|
||||
} catch (error: unknown) {
|
||||
// Error handling is done in loginWithMicrosoft function already
|
||||
console.error('Microsoft login error in form handler:', error);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue