video-query/frontend/src/auth/AuthProvider.js

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;