197 lines
8.4 KiB
JavaScript
Executable file
197 lines
8.4 KiB
JavaScript
Executable file
/*! @azure/msal-react v3.0.17 2025-08-05 */
|
|
'use strict';
|
|
import { useState, useRef, useEffect, useCallback } from 'react';
|
|
import { InteractionStatus, InteractionType, EventType, InteractionRequiredAuthError, OIDC_DEFAULT_SCOPES } from '@azure/msal-browser';
|
|
import { useIsAuthenticated } from './useIsAuthenticated.js';
|
|
import { useMsal } from './useMsal.js';
|
|
import { useAccount } from './useAccount.js';
|
|
import { ReactAuthError } from '../error/ReactAuthError.js';
|
|
|
|
/*
|
|
* Copyright (c) Microsoft Corporation. All rights reserved.
|
|
* Licensed under the MIT License.
|
|
*/
|
|
/**
|
|
* If a user is not currently signed in this hook invokes a login. Failed logins can be retried using the login callback returned.
|
|
* If a user is currently signed in this hook attempts to acquire a token. Subsequent token requests can use the acquireToken callback returned.
|
|
* Optionally provide a request object to be used in the login/acquireToken call.
|
|
* Optionally provide a specific user that should be logged in.
|
|
* @param interactionType
|
|
* @param authenticationRequest
|
|
* @param accountIdentifiers
|
|
*/
|
|
function useMsalAuthentication(interactionType, authenticationRequest, accountIdentifiers) {
|
|
const { instance, inProgress, logger } = useMsal();
|
|
const isAuthenticated = useIsAuthenticated(accountIdentifiers);
|
|
const account = useAccount(accountIdentifiers);
|
|
const [[result, error], setResponse] = useState([null, null]);
|
|
// Used to prevent state updates after unmount
|
|
const mounted = useRef(true);
|
|
useEffect(() => {
|
|
return () => {
|
|
mounted.current = false;
|
|
};
|
|
}, []);
|
|
// Boolean used to check if interaction is in progress in acquireTokenSilent fallback. Use Ref instead of state to prevent acquireToken function from being regenerated on each change to interactionInProgress value
|
|
const interactionInProgress = useRef(inProgress !== InteractionStatus.None);
|
|
useEffect(() => {
|
|
interactionInProgress.current = inProgress !== InteractionStatus.None;
|
|
}, [inProgress]);
|
|
// Flag used to control when the hook calls login/acquireToken
|
|
const shouldAcquireToken = useRef(true);
|
|
useEffect(() => {
|
|
if (!!error) {
|
|
// Errors should be handled by consuming component
|
|
shouldAcquireToken.current = false;
|
|
return;
|
|
}
|
|
if (!!result) {
|
|
// Token has already been acquired, consuming component/application is responsible for renewing
|
|
shouldAcquireToken.current = false;
|
|
return;
|
|
}
|
|
}, [error, result]);
|
|
const login = useCallback(async (callbackInteractionType, callbackRequest) => {
|
|
const loginType = callbackInteractionType || interactionType;
|
|
const loginRequest = callbackRequest || authenticationRequest;
|
|
switch (loginType) {
|
|
case InteractionType.Popup:
|
|
logger.verbose("useMsalAuthentication - Calling loginPopup");
|
|
return instance.loginPopup(loginRequest);
|
|
case InteractionType.Redirect:
|
|
// This promise is not expected to resolve due to full frame redirect
|
|
logger.verbose("useMsalAuthentication - Calling loginRedirect");
|
|
return instance
|
|
.loginRedirect(loginRequest)
|
|
.then(null);
|
|
case InteractionType.Silent:
|
|
logger.verbose("useMsalAuthentication - Calling ssoSilent");
|
|
return instance.ssoSilent(loginRequest);
|
|
default:
|
|
throw ReactAuthError.createInvalidInteractionTypeError();
|
|
}
|
|
}, [instance, interactionType, authenticationRequest, logger]);
|
|
const acquireToken = useCallback(async (callbackInteractionType, callbackRequest) => {
|
|
const fallbackInteractionType = callbackInteractionType || interactionType;
|
|
let tokenRequest;
|
|
if (callbackRequest) {
|
|
logger.trace("useMsalAuthentication - acquireToken - Using request provided in the callback");
|
|
tokenRequest = {
|
|
...callbackRequest,
|
|
};
|
|
}
|
|
else if (authenticationRequest) {
|
|
logger.trace("useMsalAuthentication - acquireToken - Using request provided in the hook");
|
|
tokenRequest = {
|
|
...authenticationRequest,
|
|
scopes: authenticationRequest.scopes || OIDC_DEFAULT_SCOPES,
|
|
};
|
|
}
|
|
else {
|
|
logger.trace("useMsalAuthentication - acquireToken - No request object provided, using default request.");
|
|
tokenRequest = {
|
|
scopes: OIDC_DEFAULT_SCOPES,
|
|
};
|
|
}
|
|
if (!tokenRequest.account && account) {
|
|
logger.trace("useMsalAuthentication - acquireToken - Attaching account to request");
|
|
tokenRequest.account = account;
|
|
}
|
|
const getToken = async () => {
|
|
logger.verbose("useMsalAuthentication - Calling acquireTokenSilent");
|
|
return instance
|
|
.acquireTokenSilent(tokenRequest)
|
|
.catch(async (e) => {
|
|
if (e instanceof InteractionRequiredAuthError) {
|
|
if (!interactionInProgress.current) {
|
|
logger.error("useMsalAuthentication - Interaction required, falling back to interaction");
|
|
return login(fallbackInteractionType, tokenRequest);
|
|
}
|
|
else {
|
|
logger.error("useMsalAuthentication - Interaction required but is already in progress. Please try again, if needed, after interaction completes.");
|
|
throw ReactAuthError.createUnableToFallbackToInteractionError();
|
|
}
|
|
}
|
|
throw e;
|
|
});
|
|
};
|
|
return getToken()
|
|
.then((response) => {
|
|
if (mounted.current) {
|
|
setResponse([response, null]);
|
|
}
|
|
return response;
|
|
})
|
|
.catch((e) => {
|
|
if (mounted.current) {
|
|
setResponse([null, e]);
|
|
}
|
|
throw e;
|
|
});
|
|
}, [
|
|
instance,
|
|
interactionType,
|
|
authenticationRequest,
|
|
logger,
|
|
account,
|
|
login,
|
|
]);
|
|
useEffect(() => {
|
|
const callbackId = instance.addEventCallback((message) => {
|
|
switch (message.eventType) {
|
|
case EventType.LOGIN_SUCCESS:
|
|
case EventType.SSO_SILENT_SUCCESS:
|
|
if (message.payload) {
|
|
setResponse([
|
|
message.payload,
|
|
null,
|
|
]);
|
|
}
|
|
break;
|
|
case EventType.LOGIN_FAILURE:
|
|
case EventType.SSO_SILENT_FAILURE:
|
|
if (message.error) {
|
|
setResponse([null, message.error]);
|
|
}
|
|
break;
|
|
}
|
|
});
|
|
logger.verbose(`useMsalAuthentication - Registered event callback with id: ${callbackId}`);
|
|
return () => {
|
|
if (callbackId) {
|
|
logger.verbose(`useMsalAuthentication - Removing event callback ${callbackId}`);
|
|
instance.removeEventCallback(callbackId);
|
|
}
|
|
};
|
|
}, [instance, logger]);
|
|
useEffect(() => {
|
|
if (shouldAcquireToken.current &&
|
|
inProgress === InteractionStatus.None) {
|
|
if (!isAuthenticated) {
|
|
shouldAcquireToken.current = false;
|
|
logger.info("useMsalAuthentication - No user is authenticated, attempting to login");
|
|
login().catch(() => {
|
|
// Errors are saved in state above
|
|
return;
|
|
});
|
|
}
|
|
else if (account) {
|
|
shouldAcquireToken.current = false;
|
|
logger.info("useMsalAuthentication - User is authenticated, attempting to acquire token");
|
|
acquireToken().catch(() => {
|
|
// Errors are saved in state above
|
|
return;
|
|
});
|
|
}
|
|
}
|
|
}, [isAuthenticated, account, inProgress, login, acquireToken, logger]);
|
|
return {
|
|
login,
|
|
acquireToken,
|
|
result,
|
|
error,
|
|
};
|
|
}
|
|
|
|
export { useMsalAuthentication };
|
|
//# sourceMappingURL=useMsalAuthentication.js.map
|