@azure/msal-browser
Version:
Microsoft Authentication Library for js
242 lines (239 loc) • 13.8 kB
JavaScript
/*! @azure/msal-browser v4.21.0 2025-08-19 */
'use strict';
import { CustomAuthApiError } from '../../core/error/CustomAuthApiError.mjs';
import { UNSUPPORTED_CHALLENGE_TYPE, ATTRIBUTES_REQUIRED, CREDENTIAL_REQUIRED, INVALID_RESPONSE_BODY, CONTINUATION_TOKEN_MISSING } from '../../core/network_client/custom_auth_api/types/ApiErrorCodes.mjs';
import { UnexpectedError } from '../../core/error/UnexpectedError.mjs';
import { CustomAuthInteractionClientBase } from '../../core/interaction_client/CustomAuthInteractionClientBase.mjs';
import { SIGN_UP_START, SIGN_UP_WITH_PASSWORD_START, SIGN_UP_SUBMIT_CODE, SIGN_UP_SUBMIT_PASSWORD, SIGN_UP_SUBMIT_ATTRIBUTES, SIGN_UP_RESEND_CODE } from '../../core/telemetry/PublicApiId.mjs';
import { ChallengeType, DefaultCustomAuthApiCodeResendIntervalInSec, DefaultCustomAuthApiCodeLength } from '../../CustomAuthConstants.mjs';
import { SIGN_UP_CODE_REQUIRED_RESULT_TYPE, SIGN_UP_PASSWORD_REQUIRED_RESULT_TYPE, SIGN_UP_ATTRIBUTES_REQUIRED_RESULT_TYPE, createSignUpCodeRequiredResult, createSignUpPasswordRequiredResult, createSignUpCompletedResult, createSignUpAttributesRequiredResult } from './result/SignUpActionResult.mjs';
/*
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License.
*/
class SignUpClient extends CustomAuthInteractionClientBase {
/**
* Starts the sign up flow.
* @param parameters The parameters for the sign up start action.
* @returns The result of the sign up start action.
*/
async start(parameters) {
const apiId = !parameters.password
? SIGN_UP_START
: SIGN_UP_WITH_PASSWORD_START;
const telemetryManager = this.initializeServerTelemetryManager(apiId);
const startRequest = {
username: parameters.username,
password: parameters.password,
attributes: parameters.attributes,
challenge_type: this.getChallengeTypes(parameters.challengeType),
telemetryManager,
correlationId: parameters.correlationId,
};
this.logger.verbose("Calling start endpoint for sign up.", parameters.correlationId);
const startResponse = await this.customAuthApiClient.signUpApi.start(startRequest);
this.logger.verbose("Start endpoint called for sign up.", parameters.correlationId);
const challengeRequest = {
continuation_token: startResponse.continuation_token ?? "",
challenge_type: this.getChallengeTypes(parameters.challengeType),
telemetryManager,
correlationId: startResponse.correlation_id,
};
return this.performChallengeRequest(challengeRequest);
}
/**
* Submits the code for the sign up flow.
* @param parameters The parameters for the sign up submit code action.
* @returns The result of the sign up submit code action.
*/
async submitCode(parameters) {
const apiId = SIGN_UP_SUBMIT_CODE;
const telemetryManager = this.initializeServerTelemetryManager(apiId);
const requestSubmitCode = {
continuation_token: parameters.continuationToken,
oob: parameters.code,
telemetryManager,
correlationId: parameters.correlationId,
};
const result = await this.performContinueRequest("SignUpClient.submitCode", parameters, telemetryManager, () => this.customAuthApiClient.signUpApi.continueWithCode(requestSubmitCode), parameters.correlationId);
if (result.type === SIGN_UP_CODE_REQUIRED_RESULT_TYPE) {
throw new CustomAuthApiError(UNSUPPORTED_CHALLENGE_TYPE, "The challenge type 'oob' is invalid after submtting code for sign up.", parameters.correlationId);
}
return result;
}
/**
* Submits the password for the sign up flow.
* @param parameter The parameters for the sign up submit password action.
* @returns The result of the sign up submit password action.
*/
async submitPassword(parameter) {
const apiId = SIGN_UP_SUBMIT_PASSWORD;
const telemetryManager = this.initializeServerTelemetryManager(apiId);
const requestSubmitPwd = {
continuation_token: parameter.continuationToken,
password: parameter.password,
telemetryManager,
correlationId: parameter.correlationId,
};
const result = await this.performContinueRequest("SignUpClient.submitPassword", parameter, telemetryManager, () => this.customAuthApiClient.signUpApi.continueWithPassword(requestSubmitPwd), parameter.correlationId);
if (result.type === SIGN_UP_PASSWORD_REQUIRED_RESULT_TYPE) {
throw new CustomAuthApiError(UNSUPPORTED_CHALLENGE_TYPE, "The challenge type 'password' is invalid after submtting password for sign up.", parameter.correlationId);
}
return result;
}
/**
* Submits the attributes for the sign up flow.
* @param parameter The parameters for the sign up submit attributes action.
* @returns The result of the sign up submit attributes action.
*/
async submitAttributes(parameter) {
const apiId = SIGN_UP_SUBMIT_ATTRIBUTES;
const telemetryManager = this.initializeServerTelemetryManager(apiId);
const reqWithAttr = {
continuation_token: parameter.continuationToken,
attributes: parameter.attributes,
telemetryManager,
correlationId: parameter.correlationId,
};
const result = await this.performContinueRequest("SignUpClient.submitAttributes", parameter, telemetryManager, () => this.customAuthApiClient.signUpApi.continueWithAttributes(reqWithAttr), parameter.correlationId);
if (result.type === SIGN_UP_ATTRIBUTES_REQUIRED_RESULT_TYPE) {
throw new CustomAuthApiError(ATTRIBUTES_REQUIRED, "User attributes required", parameter.correlationId, [], "", result.requiredAttributes, result.continuationToken);
}
return result;
}
/**
* Resends the code for the sign up flow.
* @param parameters The parameters for the sign up resend code action.
* @returns The result of the sign up resend code action.
*/
async resendCode(parameters) {
const apiId = SIGN_UP_RESEND_CODE;
const telemetryManager = this.initializeServerTelemetryManager(apiId);
const challengeRequest = {
continuation_token: parameters.continuationToken ?? "",
challenge_type: this.getChallengeTypes(parameters.challengeType),
telemetryManager,
correlationId: parameters.correlationId,
};
const result = await this.performChallengeRequest(challengeRequest);
if (result.type === SIGN_UP_PASSWORD_REQUIRED_RESULT_TYPE) {
throw new CustomAuthApiError(UNSUPPORTED_CHALLENGE_TYPE, "The challenge type 'password' is invalid after resending code for sign up.", parameters.correlationId);
}
return result;
}
async performChallengeRequest(request) {
this.logger.verbose("Calling challenge endpoint for sign up.", request.correlationId);
const challengeResponse = await this.customAuthApiClient.signUpApi.requestChallenge(request);
this.logger.verbose("Challenge endpoint called for sign up.", request.correlationId);
if (challengeResponse.challenge_type === ChallengeType.OOB) {
// Code is required
this.logger.verbose("Challenge type is oob for sign up.", request.correlationId);
return createSignUpCodeRequiredResult({
correlationId: challengeResponse.correlation_id,
continuationToken: challengeResponse.continuation_token ?? "",
challengeChannel: challengeResponse.challenge_channel ?? "",
challengeTargetLabel: challengeResponse.challenge_target_label ?? "",
codeLength: challengeResponse.code_length ??
DefaultCustomAuthApiCodeLength,
interval: challengeResponse.interval ??
DefaultCustomAuthApiCodeResendIntervalInSec,
bindingMethod: challengeResponse.binding_method ?? "",
});
}
if (challengeResponse.challenge_type === ChallengeType.PASSWORD) {
// Password is required
this.logger.verbose("Challenge type is password for sign up.", request.correlationId);
return createSignUpPasswordRequiredResult({
correlationId: challengeResponse.correlation_id,
continuationToken: challengeResponse.continuation_token ?? "",
});
}
this.logger.error(`Unsupported challenge type '${challengeResponse.challenge_type}' for sign up.`, request.correlationId);
throw new CustomAuthApiError(UNSUPPORTED_CHALLENGE_TYPE, `Unsupported challenge type '${challengeResponse.challenge_type}'.`, request.correlationId);
}
async performContinueRequest(callerName, requestParams, telemetryManager, responseGetter, requestCorrelationId) {
this.logger.verbose(`${callerName} is calling continue endpoint for sign up.`, requestCorrelationId);
try {
const response = await responseGetter();
this.logger.verbose(`Continue endpoint called by ${callerName} for sign up.`, requestCorrelationId);
return createSignUpCompletedResult({
correlationId: requestCorrelationId,
continuationToken: response.continuation_token ?? "",
});
}
catch (error) {
if (error instanceof CustomAuthApiError) {
return this.handleContinueResponseError(error, error.correlationId ?? requestCorrelationId, requestParams, telemetryManager);
}
else {
this.logger.errorPii(`${callerName} is failed to call continue endpoint for sign up. Error: ${error}`, requestCorrelationId);
throw new UnexpectedError(error, requestCorrelationId);
}
}
}
async handleContinueResponseError(responseError, correlationId, requestParams, telemetryManager) {
if (responseError.error ===
CREDENTIAL_REQUIRED &&
!!responseError.errorCodes &&
responseError.errorCodes.includes(55103)) {
// Credential is required
this.logger.verbose("The credential is required in the sign up flow.", correlationId);
const continuationToken = this.readContinuationTokenFromResponeError(responseError);
// Call the challenge endpoint to ensure the password challenge type is supported.
const challengeRequest = {
continuation_token: continuationToken,
challenge_type: this.getChallengeTypes(requestParams.challengeType),
telemetryManager,
correlationId,
};
const challengeResult = await this.performChallengeRequest(challengeRequest);
if (challengeResult.type === SIGN_UP_PASSWORD_REQUIRED_RESULT_TYPE) {
return createSignUpPasswordRequiredResult({
correlationId: correlationId,
continuationToken: challengeResult.continuationToken,
});
}
if (challengeResult.type === SIGN_UP_CODE_REQUIRED_RESULT_TYPE) {
return createSignUpCodeRequiredResult({
correlationId: challengeResult.correlationId,
continuationToken: challengeResult.continuationToken,
challengeChannel: challengeResult.challengeChannel,
challengeTargetLabel: challengeResult.challengeTargetLabel,
codeLength: challengeResult.codeLength,
interval: challengeResult.interval,
bindingMethod: challengeResult.bindingMethod,
});
}
throw new CustomAuthApiError(UNSUPPORTED_CHALLENGE_TYPE, "The challenge type is not supported.", correlationId);
}
if (this.isAttributesRequiredError(responseError, correlationId)) {
// Attributes are required
this.logger.verbose("Attributes are required in the sign up flow.", correlationId);
const continuationToken = this.readContinuationTokenFromResponeError(responseError);
return createSignUpAttributesRequiredResult({
correlationId: correlationId,
continuationToken: continuationToken,
requiredAttributes: responseError.attributes ?? [],
});
}
throw responseError;
}
isAttributesRequiredError(responseError, correlationId) {
if (responseError.error === ATTRIBUTES_REQUIRED) {
if (!responseError.attributes ||
responseError.attributes.length === 0) {
throw new CustomAuthApiError(INVALID_RESPONSE_BODY, "Attributes are required but required_attributes field is missing in the response body.", correlationId);
}
return true;
}
return false;
}
readContinuationTokenFromResponeError(responseError) {
if (!responseError.continuationToken) {
throw new CustomAuthApiError(CONTINUATION_TOKEN_MISSING, "Continuation token is missing in the response body", responseError.correlationId);
}
return responseError.continuationToken;
}
}
export { SignUpClient };
//# sourceMappingURL=SignUpClient.mjs.map