@azure/msal-browser
Version:
Microsoft Authentication Library for js
185 lines (165 loc) • 7.07 kB
text/typescript
/*
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License.
*/
import { CustomAuthInteractionClientBase } from "../CustomAuthInteractionClientBase.js";
import {
JitChallengeAuthMethodParams,
JitSubmitChallengeParams,
} from "./parameter/JitParams.js";
import {
JitVerificationRequiredResult,
JitCompletedResult,
createJitVerificationRequiredResult,
createJitCompletedResult,
} from "./result/JitActionResult.js";
import {
DefaultCustomAuthApiCodeLength,
ChallengeType,
GrantType,
} from "../../../CustomAuthConstants.js";
import * as PublicApiId from "../../telemetry/PublicApiId.js";
import {
RegisterChallengeRequest,
RegisterContinueRequest,
SignInContinuationTokenRequest,
} from "../../network_client/custom_auth_api/types/ApiRequestTypes.js";
import { initializeServerTelemetryManager } from "../../../../interaction_client/BaseInteractionClient.js";
/**
* JIT client for handling just-in-time authentication method registration flows.
*/
export class JitClient extends CustomAuthInteractionClientBase {
/**
* Challenges an authentication method for JIT registration.
* @param parameters The parameters for challenging the auth method.
* @returns Promise that resolves to either JitVerificationRequiredResult or JitCompletedResult.
*/
async challengeAuthMethod(
parameters: JitChallengeAuthMethodParams
): Promise<JitVerificationRequiredResult | JitCompletedResult> {
const correlationId = parameters.correlationId || this.correlationId;
const apiId = PublicApiId.JIT_CHALLENGE_AUTH_METHOD;
const telemetryManager = initializeServerTelemetryManager(
apiId,
this.config.auth.clientId,
correlationId,
this.browserStorage,
this.logger
);
this.logger.verbose(
"Calling challenge endpoint for getting auth method.",
correlationId
);
const challengeReq: RegisterChallengeRequest = {
continuation_token: parameters.continuationToken,
challenge_type: parameters.authMethod.challenge_type,
challenge_target: parameters.verificationContact,
challenge_channel: parameters.authMethod.challenge_channel,
correlationId: correlationId,
telemetryManager: telemetryManager,
};
const challengeResponse =
await this.customAuthApiClient.registerApi.challenge(challengeReq);
this.logger.verbose(
"Challenge endpoint called for auth method registration.",
challengeResponse.correlation_id || correlationId
);
/*
* Handle fast-pass scenario (preverified)
* This occurs when the user selects the same email used during sign-up
* Since the email was already verified during sign-up, no additional verification is needed
*/
if (challengeResponse.challenge_type === ChallengeType.PREVERIFIED) {
this.logger.verbose(
"Fast-pass scenario detected - completing registration without additional verification.",
challengeResponse.correlation_id || correlationId
);
// Use submitChallenge for fast-pass scenario with continuation_token grant type
const fastPassParams: JitSubmitChallengeParams = {
correlationId:
challengeResponse.correlation_id || correlationId,
continuationToken: challengeResponse.continuation_token,
grantType: GrantType.CONTINUATION_TOKEN,
scopes: parameters.scopes,
username: parameters.username,
claims: parameters.claims,
};
const completedResult = await this.submitChallenge(fastPassParams);
return completedResult;
}
// Verification required
return createJitVerificationRequiredResult({
correlationId: challengeResponse.correlation_id || correlationId,
continuationToken: challengeResponse.continuation_token,
challengeChannel: challengeResponse.challenge_channel,
challengeTargetLabel: challengeResponse.challenge_target,
codeLength:
challengeResponse.code_length || DefaultCustomAuthApiCodeLength,
});
}
/**
* Submits challenge response and completes JIT registration.
* @param parameters The parameters for submitting the challenge.
* @returns Promise that resolves to JitCompletedResult.
*/
async submitChallenge(
parameters: JitSubmitChallengeParams
): Promise<JitCompletedResult> {
const correlationId = parameters.correlationId || this.correlationId;
const apiId = PublicApiId.JIT_SUBMIT_CHALLENGE;
const telemetryManager = initializeServerTelemetryManager(
apiId,
this.config.auth.clientId,
correlationId,
this.browserStorage,
this.logger
);
this.logger.verbose(
"Calling continue endpoint for auth method challenge submission.",
correlationId
);
// Submit challenge to complete registration
const continueReq: RegisterContinueRequest = {
continuation_token: parameters.continuationToken,
grant_type: parameters.grantType,
...(parameters.challenge && {
oob: parameters.challenge,
}),
correlationId: correlationId,
telemetryManager: telemetryManager,
};
const continueResponse =
await this.customAuthApiClient.registerApi.continue(continueReq);
this.logger.verbose(
"Continue endpoint called for auth method challenge submission.",
parameters.correlationId
);
// Use continuation token to get authentication tokens
const scopes = this.getScopes(parameters.scopes);
const tokenRequest: SignInContinuationTokenRequest = {
continuation_token: continueResponse.continuation_token,
scope: scopes.join(" "),
correlationId: continueResponse.correlation_id || correlationId,
telemetryManager: telemetryManager,
...(parameters.claims && {
claims: parameters.claims,
}),
};
const tokenResponse =
await this.customAuthApiClient.signInApi.requestTokenWithContinuationToken(
tokenRequest
);
const authResult = await this.handleTokenResponse(
tokenResponse,
scopes,
tokenResponse.correlation_id ||
continueResponse.correlation_id ||
correlationId,
apiId
);
return createJitCompletedResult({
correlationId: continueResponse.correlation_id || correlationId,
authenticationResult: authResult,
});
}
}