UNPKG

@azure/msal-browser

Version:
281 lines (278 loc) 16.6 kB
/*! @azure/msal-browser v4.21.0 2025-08-19 */ 'use strict'; import { GetAccountResult } from '../get_account/auth_flow/result/GetAccountResult.mjs'; import { SignInResult } from '../sign_in/auth_flow/result/SignInResult.mjs'; import { SignUpResult } from '../sign_up/auth_flow/result/SignUpResult.mjs'; import { SignInClient } from '../sign_in/interaction_client/SignInClient.mjs'; import { CustomAuthAccountData } from '../get_account/auth_flow/CustomAuthAccountData.mjs'; import { UnexpectedError } from '../core/error/UnexpectedError.mjs'; import { ResetPasswordStartResult } from '../reset_password/auth_flow/result/ResetPasswordStartResult.mjs'; import { CustomAuthAuthority } from '../core/CustomAuthAuthority.mjs'; import { DefaultPackageInfo } from '../CustomAuthConstants.mjs'; import { SIGN_IN_CODE_SEND_RESULT_TYPE, SIGN_IN_PASSWORD_REQUIRED_RESULT_TYPE } from '../sign_in/interaction_client/result/SignInActionResult.mjs'; import { SignUpClient } from '../sign_up/interaction_client/SignUpClient.mjs'; import { CustomAuthInterationClientFactory } from '../core/interaction_client/CustomAuthInterationClientFactory.mjs'; import { SIGN_UP_CODE_REQUIRED_RESULT_TYPE, SIGN_UP_PASSWORD_REQUIRED_RESULT_TYPE } from '../sign_up/interaction_client/result/SignUpActionResult.mjs'; import { CustomAuthApiClient } from '../core/network_client/custom_auth_api/CustomAuthApiClient.mjs'; import { FetchHttpClient } from '../core/network_client/http_client/FetchHttpClient.mjs'; import { ResetPasswordClient } from '../reset_password/interaction_client/ResetPasswordClient.mjs'; import { NoCachedAccountFoundError } from '../core/error/NoCachedAccountFoundError.mjs'; import { ensureArgumentIsNotNullOrUndefined, ensureArgumentIsNotEmptyString, ensureArgumentIsJSONString } from '../core/utils/ArgumentValidator.mjs'; import { UserAlreadySignedInError } from '../core/error/UserAlreadySignedInError.mjs'; import { CustomAuthSilentCacheClient } from '../get_account/interaction_client/CustomAuthSilentCacheClient.mjs'; import { UnsupportedEnvironmentError } from '../core/error/UnsupportedEnvironmentError.mjs'; import { SignInCodeRequiredState } from '../sign_in/auth_flow/state/SignInCodeRequiredState.mjs'; import { SignInPasswordRequiredState } from '../sign_in/auth_flow/state/SignInPasswordRequiredState.mjs'; import { SignInCompletedState } from '../sign_in/auth_flow/state/SignInCompletedState.mjs'; import { SignUpCodeRequiredState } from '../sign_up/auth_flow/state/SignUpCodeRequiredState.mjs'; import { SignUpPasswordRequiredState } from '../sign_up/auth_flow/state/SignUpPasswordRequiredState.mjs'; import { ResetPasswordCodeRequiredState } from '../reset_password/auth_flow/state/ResetPasswordCodeRequiredState.mjs'; import { StandardController } from '../../controllers/StandardController.mjs'; /* * Copyright (c) Microsoft Corporation. All rights reserved. * Licensed under the MIT License. */ /* * Controller for standard native auth operations. */ class CustomAuthStandardController extends StandardController { /* * Constructor for CustomAuthStandardController. * @param operatingContext - The operating context for the controller. * @param customAuthApiClient - The client to use for custom auth API operations. */ constructor(operatingContext, customAuthApiClient) { super(operatingContext); if (!this.isBrowserEnvironment) { this.logger.verbose("The SDK can only be used in a browser environment."); throw new UnsupportedEnvironmentError(); } this.logger = this.logger.clone(DefaultPackageInfo.SKU, DefaultPackageInfo.VERSION); this.customAuthConfig = operatingContext.getCustomAuthConfig(); this.authority = new CustomAuthAuthority(this.customAuthConfig.auth.authority, this.customAuthConfig, this.networkClient, this.browserStorage, this.logger, this.customAuthConfig.customAuth?.authApiProxyUrl); const interactionClientFactory = new CustomAuthInterationClientFactory(this.customAuthConfig, this.browserStorage, this.browserCrypto, this.logger, this.eventHandler, this.navigationClient, this.performanceClient, customAuthApiClient ?? new CustomAuthApiClient(this.authority.getCustomAuthApiDomain(), this.customAuthConfig.auth.clientId, new FetchHttpClient(this.logger)), this.authority); this.signInClient = interactionClientFactory.create(SignInClient); this.signUpClient = interactionClientFactory.create(SignUpClient); this.resetPasswordClient = interactionClientFactory.create(ResetPasswordClient); this.cacheClient = interactionClientFactory.create(CustomAuthSilentCacheClient); } /* * Gets the current account from the cache. * @param accountRetrievalInputs - Inputs for getting the current cached account * @returns {GetAccountResult} The account result */ getCurrentAccount(accountRetrievalInputs) { const correlationId = this.getCorrelationId(accountRetrievalInputs); try { this.logger.verbose("Getting current account data.", correlationId); const account = this.cacheClient.getCurrentAccount(correlationId); if (account) { this.logger.verbose("Account data found.", correlationId); return new GetAccountResult(new CustomAuthAccountData(account, this.customAuthConfig, this.cacheClient, this.logger, correlationId)); } throw new NoCachedAccountFoundError(correlationId); } catch (error) { this.logger.errorPii(`An error occurred during getting current account: ${error}`, correlationId); return GetAccountResult.createWithError(error); } } /* * Signs the user in. * @param signInInputs - Inputs for signing in the user. * @returns {Promise<SignInResult>} The result of the operation. */ async signIn(signInInputs) { const correlationId = this.getCorrelationId(signInInputs); try { ensureArgumentIsNotNullOrUndefined("signInInputs", signInInputs, correlationId); ensureArgumentIsNotEmptyString("signInInputs.username", signInInputs.username, correlationId); this.ensureUserNotSignedIn(correlationId); if (signInInputs.claims) { ensureArgumentIsJSONString("signInInputs.claims", signInInputs.claims, correlationId); } // start the signin flow const signInStartParams = { clientId: this.customAuthConfig.auth.clientId, correlationId: correlationId, challengeType: this.customAuthConfig.customAuth.challengeTypes ?? [], username: signInInputs.username, password: signInInputs.password, }; this.logger.verbose(`Starting sign-in flow ${!!signInInputs.password ? "with" : "without"} password.`, correlationId); const startResult = await this.signInClient.start(signInStartParams); this.logger.verbose("Sign-in flow started.", correlationId); if (startResult.type === SIGN_IN_CODE_SEND_RESULT_TYPE) { // require code this.logger.verbose("Code required for sign-in.", correlationId); return new SignInResult(new SignInCodeRequiredState({ correlationId: startResult.correlationId, continuationToken: startResult.continuationToken, logger: this.logger, config: this.customAuthConfig, signInClient: this.signInClient, cacheClient: this.cacheClient, username: signInInputs.username, codeLength: startResult.codeLength, scopes: signInInputs.scopes ?? [], claims: signInInputs.claims, })); } else if (startResult.type === SIGN_IN_PASSWORD_REQUIRED_RESULT_TYPE) { // require password this.logger.verbose("Password required for sign-in.", correlationId); if (!signInInputs.password) { this.logger.verbose("Password required but not provided. Returning password required state.", correlationId); return new SignInResult(new SignInPasswordRequiredState({ correlationId: startResult.correlationId, continuationToken: startResult.continuationToken, logger: this.logger, config: this.customAuthConfig, signInClient: this.signInClient, cacheClient: this.cacheClient, username: signInInputs.username, scopes: signInInputs.scopes ?? [], claims: signInInputs.claims, })); } this.logger.verbose("Submitting password for sign-in.", correlationId); // if the password is provided, then try to get token silently. const submitPasswordParams = { clientId: this.customAuthConfig.auth.clientId, correlationId: correlationId, challengeType: this.customAuthConfig.customAuth.challengeTypes ?? [], scopes: signInInputs.scopes ?? [], continuationToken: startResult.continuationToken, password: signInInputs.password, username: signInInputs.username, claims: signInInputs.claims, }; const completedResult = await this.signInClient.submitPassword(submitPasswordParams); this.logger.verbose("Sign-in flow completed.", correlationId); const accountInfo = new CustomAuthAccountData(completedResult.authenticationResult.account, this.customAuthConfig, this.cacheClient, this.logger, correlationId); return new SignInResult(new SignInCompletedState(), accountInfo); } this.logger.error("Unexpected sign-in result type. Returning error.", correlationId); throw new UnexpectedError("Unknow sign-in result type", correlationId); } catch (error) { this.logger.errorPii(`An error occurred during starting sign-in: ${error}`, correlationId); return SignInResult.createWithError(error); } } /* * Signs the user up. * @param signUpInputs - Inputs for signing up the user. * @returns {Promise<SignUpResult>} The result of the operation */ async signUp(signUpInputs) { const correlationId = this.getCorrelationId(signUpInputs); try { ensureArgumentIsNotNullOrUndefined("signUpInputs", signUpInputs, correlationId); ensureArgumentIsNotEmptyString("signUpInputs.username", signUpInputs.username, correlationId); this.ensureUserNotSignedIn(correlationId); this.logger.verbose(`Starting sign-up flow${!!signUpInputs.password ? ` with ${!!signUpInputs.attributes ? "password and attributes" : "password"}` : ""}.`, correlationId); const startResult = await this.signUpClient.start({ clientId: this.customAuthConfig.auth.clientId, correlationId: correlationId, challengeType: this.customAuthConfig.customAuth.challengeTypes ?? [], username: signUpInputs.username, password: signUpInputs.password, attributes: signUpInputs.attributes, }); this.logger.verbose("Sign-up flow started.", correlationId); if (startResult.type === SIGN_UP_CODE_REQUIRED_RESULT_TYPE) { // Code required this.logger.verbose("Code required for sign-up.", correlationId); return new SignUpResult(new SignUpCodeRequiredState({ correlationId: startResult.correlationId, continuationToken: startResult.continuationToken, logger: this.logger, config: this.customAuthConfig, signInClient: this.signInClient, signUpClient: this.signUpClient, cacheClient: this.cacheClient, username: signUpInputs.username, codeLength: startResult.codeLength, codeResendInterval: startResult.interval, })); } else if (startResult.type === SIGN_UP_PASSWORD_REQUIRED_RESULT_TYPE) { // Password required this.logger.verbose("Password required for sign-up.", correlationId); return new SignUpResult(new SignUpPasswordRequiredState({ correlationId: startResult.correlationId, continuationToken: startResult.continuationToken, logger: this.logger, config: this.customAuthConfig, signInClient: this.signInClient, signUpClient: this.signUpClient, cacheClient: this.cacheClient, username: signUpInputs.username, })); } this.logger.error("Unexpected sign-up result type. Returning error.", correlationId); throw new UnexpectedError("Unknown sign-up result type", correlationId); } catch (error) { this.logger.errorPii(`An error occurred during starting sign-up: ${error}`, correlationId); return SignUpResult.createWithError(error); } } /* * Resets the user's password. * @param resetPasswordInputs - Inputs for resetting the user's password. * @returns {Promise<ResetPasswordStartResult>} The result of the operation. */ async resetPassword(resetPasswordInputs) { const correlationId = this.getCorrelationId(resetPasswordInputs); try { ensureArgumentIsNotNullOrUndefined("resetPasswordInputs", resetPasswordInputs, correlationId); ensureArgumentIsNotEmptyString("resetPasswordInputs.username", resetPasswordInputs.username, correlationId); this.ensureUserNotSignedIn(correlationId); this.logger.verbose("Starting password-reset flow.", correlationId); const startResult = await this.resetPasswordClient.start({ clientId: this.customAuthConfig.auth.clientId, correlationId: correlationId, challengeType: this.customAuthConfig.customAuth.challengeTypes ?? [], username: resetPasswordInputs.username, }); this.logger.verbose("Password-reset flow started.", correlationId); return new ResetPasswordStartResult(new ResetPasswordCodeRequiredState({ correlationId: startResult.correlationId, continuationToken: startResult.continuationToken, logger: this.logger, config: this.customAuthConfig, signInClient: this.signInClient, resetPasswordClient: this.resetPasswordClient, cacheClient: this.cacheClient, username: resetPasswordInputs.username, codeLength: startResult.codeLength, })); } catch (error) { this.logger.errorPii(`An error occurred during starting reset-password: ${error}`, correlationId); return ResetPasswordStartResult.createWithError(error); } } getCorrelationId(actionInputs) { return (actionInputs?.correlationId || this.browserCrypto.createNewGuid()); } ensureUserNotSignedIn(correlationId) { const account = this.getCurrentAccount({ correlationId: correlationId, }); if (account && !!account.data) { this.logger.error("User has already signed in.", correlationId); throw new UserAlreadySignedInError(correlationId); } } } export { CustomAuthStandardController }; //# sourceMappingURL=CustomAuthStandardController.mjs.map