172 lines
No EOL
6.8 KiB
JavaScript
172 lines
No EOL
6.8 KiB
JavaScript
import React, { useEffect, useState } from 'react';
|
|
import { MsalProvider } from '@azure/msal-react';
|
|
import { PublicClientApplication, EventType, InteractionType } from '@azure/msal-browser';
|
|
import { loadConfig, getMsalConfig } from '../utils/configLoader';
|
|
|
|
// MSAL instance will be created after config is loaded
|
|
let msalInstance = null;
|
|
|
|
// Create MSAL instance with loaded configuration
|
|
const createMsalInstance = async () => {
|
|
try {
|
|
console.log("Loading configuration for MSAL...");
|
|
await loadConfig();
|
|
|
|
const msalConfig = getMsalConfig();
|
|
console.log("Creating MSAL instance with runtime config...");
|
|
|
|
const instance = new PublicClientApplication(msalConfig);
|
|
|
|
console.log("Initializing MSAL instance...");
|
|
await instance.initialize();
|
|
console.log("MSAL instance initialized successfully");
|
|
|
|
// Try to set active account after initialization
|
|
if (!instance.getActiveAccount() && instance.getAllAccounts().length > 0) {
|
|
console.log("Setting active account during initialization");
|
|
instance.setActiveAccount(instance.getAllAccounts()[0]);
|
|
}
|
|
|
|
// Handle any initial redirect response at startup
|
|
try {
|
|
console.log("Checking for redirect response at startup...");
|
|
const response = await instance.handleRedirectPromise();
|
|
if (response) {
|
|
console.log("Found redirect response at startup:", response);
|
|
if (response.account) {
|
|
console.log("Setting active account from redirect response:", response.account.name);
|
|
instance.setActiveAccount(response.account);
|
|
}
|
|
} else {
|
|
console.log("No redirect response at startup");
|
|
}
|
|
} catch (redirectErr) {
|
|
console.error("Error handling redirect at startup:", redirectErr);
|
|
}
|
|
|
|
// Configure event callbacks for authentication events
|
|
instance.addEventCallback((event) => {
|
|
// Handle successful logins
|
|
if (event.eventType === EventType.LOGIN_SUCCESS) {
|
|
console.log("Login success event triggered", event);
|
|
if (event.payload && event.payload.account) {
|
|
console.log("Setting active account from event:", event.payload.account.name);
|
|
instance.setActiveAccount(event.payload.account);
|
|
// Force reload to update authentication state
|
|
if (event.interactionType === "redirect") {
|
|
window.location.reload();
|
|
}
|
|
}
|
|
}
|
|
// Handle login failures
|
|
else if (event.eventType === EventType.LOGIN_FAILURE) {
|
|
console.error("Login failure:", event.error);
|
|
}
|
|
// Handle successful silent token acquisitions
|
|
else if (event.eventType === EventType.ACQUIRE_TOKEN_SUCCESS) {
|
|
console.log("Token acquisition successful", event);
|
|
}
|
|
// Handle token acquisition failures
|
|
else if (event.eventType === EventType.ACQUIRE_TOKEN_FAILURE) {
|
|
console.error("Token acquisition failed:", event.error);
|
|
// If the error is due to an expired token, try to handle it
|
|
if (event.error && event.error.errorCode === "consent_required") {
|
|
console.log("Consent required, prompting for login");
|
|
}
|
|
}
|
|
// Log when user logs out
|
|
else if (event.eventType === EventType.LOGOUT_SUCCESS) {
|
|
console.log("Logout successful");
|
|
}
|
|
// Handle redirect success
|
|
else if (event.eventType === EventType.HANDLE_REDIRECT_END) {
|
|
console.log("Redirect handling completed");
|
|
}
|
|
});
|
|
|
|
console.log("Event callbacks registered");
|
|
return instance;
|
|
|
|
} catch (error) {
|
|
console.error("Error creating MSAL instance:", error);
|
|
throw error;
|
|
}
|
|
};
|
|
|
|
// Export getter for MSAL instance
|
|
export const getMsalInstance = () => {
|
|
return msalInstance;
|
|
};
|
|
|
|
/**
|
|
* MSAL Provider Component to wrap the application with authentication context
|
|
*/
|
|
export const AuthProvider = ({ children }) => {
|
|
const [isInitialized, setIsInitialized] = useState(false);
|
|
const [initError, setInitError] = useState(null);
|
|
|
|
// Initialize MSAL on component mount
|
|
useEffect(() => {
|
|
const initialize = async () => {
|
|
try {
|
|
console.log("AuthProvider: Starting initialization...");
|
|
msalInstance = await createMsalInstance();
|
|
console.log("AuthProvider: MSAL instance created successfully");
|
|
setIsInitialized(true);
|
|
} catch (error) {
|
|
console.error("AuthProvider: Error during initialization:", error);
|
|
setInitError(error);
|
|
setIsInitialized(true); // Mark as initialized even on error to show error message
|
|
}
|
|
};
|
|
|
|
initialize();
|
|
}, []);
|
|
|
|
// Show loading until MSAL is initialized
|
|
if (!isInitialized) {
|
|
return (
|
|
<div className="d-flex justify-content-center align-items-center" style={{ height: '100vh' }}>
|
|
<div className="spinner-border text-primary" role="status">
|
|
<span className="visually-hidden">Loading configuration...</span>
|
|
</div>
|
|
<p className="ms-3">Loading configuration and initializing authentication...</p>
|
|
</div>
|
|
);
|
|
}
|
|
|
|
// Show error if initialization failed
|
|
if (initError) {
|
|
return (
|
|
<div className="d-flex justify-content-center align-items-center" style={{ height: '100vh' }}>
|
|
<div className="alert alert-danger" role="alert">
|
|
<h4 className="alert-heading">Configuration Error</h4>
|
|
<p>Failed to load application configuration:</p>
|
|
<p><strong>{initError.message}</strong></p>
|
|
<hr />
|
|
<p className="mb-0">Please ensure config.json is available and properly configured.</p>
|
|
</div>
|
|
</div>
|
|
);
|
|
}
|
|
|
|
// Only render MSAL provider if instance was created successfully
|
|
if (!msalInstance) {
|
|
return (
|
|
<div className="d-flex justify-content-center align-items-center" style={{ height: '100vh' }}>
|
|
<div className="alert alert-warning" role="alert">
|
|
<h4 className="alert-heading">Initialization Error</h4>
|
|
<p>MSAL instance was not created properly. Please refresh the page.</p>
|
|
</div>
|
|
</div>
|
|
);
|
|
}
|
|
|
|
return (
|
|
<MsalProvider instance={msalInstance}>
|
|
{children}
|
|
</MsalProvider>
|
|
);
|
|
};
|
|
|
|
export default AuthProvider; |