UNPKG

@azure/msal-browser

Version:
167 lines (149 loc) 5.97 kB
/* * Copyright (c) Microsoft Corporation. All rights reserved. * Licensed under the MIT License. */ import { CustomAuthInteractionClientBase } from "../CustomAuthInteractionClientBase.js"; import { MfaRequestChallengeParams, MfaSubmitChallengeParams, } from "./parameter/MfaClientParameters.js"; import { MfaVerificationRequiredResult, MfaCompletedResult, createMfaVerificationRequiredResult, createMfaCompletedResult, } from "./result/MfaActionResult.js"; import { DefaultCustomAuthApiCodeLength, ChallengeType, GrantType, } from "../../../CustomAuthConstants.js"; import * as PublicApiId from "../../telemetry/PublicApiId.js"; import { SignInChallengeRequest, SignInOobTokenRequest, } from "../../network_client/custom_auth_api/types/ApiRequestTypes.js"; import { ensureArgumentIsNotEmptyString } from "../../utils/ArgumentValidator.js"; import { CustomAuthApiError } from "../../error/CustomAuthApiError.js"; import * as CustomAuthApiErrorCode from "../../network_client/custom_auth_api/types/ApiErrorCodes.js"; import { initializeServerTelemetryManager } from "../../../../interaction_client/BaseInteractionClient.js"; /** * MFA client for handling multi-factor authentication flows. */ export class MfaClient extends CustomAuthInteractionClientBase { /** * Requests an MFA challenge to be sent to the user. * @param parameters The parameters for requesting the challenge. * @returns Promise that resolves to either MfaVerificationRequiredResult. */ async requestChallenge( parameters: MfaRequestChallengeParams ): Promise<MfaVerificationRequiredResult> { const apiId = PublicApiId.MFA_REQUEST_CHALLENGE; const correlationId = parameters.correlationId || this.correlationId; const telemetryManager = initializeServerTelemetryManager( apiId, this.config.auth.clientId, correlationId, this.browserStorage, this.logger ); this.logger.verbose( "Calling challenge endpoint for MFA.", correlationId ); const challengeReq: SignInChallengeRequest = { challenge_type: this.getChallengeTypes(parameters.challengeType), continuation_token: parameters.continuationToken, id: parameters.authMethodId, correlationId: correlationId, telemetryManager: telemetryManager, }; const challengeResponse = await this.customAuthApiClient.signInApi.requestChallenge( challengeReq ); this.logger.verbose( "Challenge endpoint called for MFA.", correlationId ); if (challengeResponse.challenge_type === ChallengeType.OOB) { // Verification required - code will be sent return createMfaVerificationRequiredResult({ correlationId: challengeResponse.correlation_id || correlationId, continuationToken: challengeResponse.continuation_token ?? "", challengeChannel: challengeResponse.challenge_channel ?? "", challengeTargetLabel: challengeResponse.challenge_target_label ?? "", codeLength: challengeResponse.code_length ?? DefaultCustomAuthApiCodeLength, bindingMethod: challengeResponse.binding_method ?? "", }); } this.logger.error( `Unsupported challenge type '${challengeResponse.challenge_type}' for MFA.`, challengeResponse.correlation_id || correlationId ); throw new CustomAuthApiError( CustomAuthApiErrorCode.UNSUPPORTED_CHALLENGE_TYPE, `Unsupported challenge type '${challengeResponse.challenge_type}'.`, challengeResponse.correlation_id || correlationId ); } /** * Submits the MFA challenge response (e.g., OTP code). * @param parameters The parameters for submitting the challenge. * @returns Promise that resolves to MfaCompletedResult. */ async submitChallenge( parameters: MfaSubmitChallengeParams ): Promise<MfaCompletedResult> { const correlationId = parameters.correlationId || this.correlationId; ensureArgumentIsNotEmptyString( "parameters.challenge", parameters.challenge, correlationId ); const apiId = PublicApiId.MFA_SUBMIT_CHALLENGE; const telemetryManager = initializeServerTelemetryManager( apiId, this.config.auth.clientId, correlationId, this.browserStorage, this.logger ); const scopes = this.getScopes(parameters.scopes); const request: SignInOobTokenRequest = { continuation_token: parameters.continuationToken, oob: parameters.challenge, grant_type: GrantType.MFA_OOB, scope: scopes.join(" "), correlationId: correlationId, telemetryManager: telemetryManager, ...(parameters.claims && { claims: parameters.claims, }), }; this.logger.verbose( "Calling token endpoint for MFA challenge submission.", correlationId ); const tokenResponse = await this.customAuthApiClient.signInApi.requestTokensWithOob( request ); // Save tokens and create authentication result const result = await this.handleTokenResponse( tokenResponse, scopes, tokenResponse.correlation_id || correlationId, apiId ); return createMfaCompletedResult({ correlationId: tokenResponse.correlation_id || correlationId, authenticationResult: result, }); } }