Skip to content

Commit ba6655b

Browse files
authored
Add backward compatibility support (#7962)
This pull request adds support for client capabilities in the custom authentication flows of `@azure/msal-browser`, enabling the client to declare which authentication features it supports when interacting with the Microsoft Entra backend. It also refactors how redirect-required errors are handled and simplifies error classes related to sign-in, sign-up, and password reset flows. **Custom Authentication Capabilities Support:** * Added a `capabilities` field to `CustomAuthOptions`, allowing clients to specify supported features (e.g., MFA, registration) in the configuration (`lib/msal-browser/src/custom_auth/configuration/CustomAuthConfiguration.ts`). [[1]](diffhunk://#diff-5e18147940e49db10c140f6f1547464c2ca5a6a5e49767b129568bca042d4e68R14) [[2]](diffhunk://#diff-f98ffa0d9403f1827bd9bbad2ffe5b540194bc8da456e63d52c2958cb53309bbR48-R52) * Propagated the `capabilities` array through the `CustomAuthApiClient` and down to the `SignInApiClient`, `SignupApiClient`, and `ResetPasswordApiClient` classes, which now include these capabilities in their API requests (`CustomAuthApiClient.ts`, `SignInApiClient.ts`, `SignupApiClient.ts`, `ResetPasswordApiClient.ts`). [[1]](diffhunk://#diff-e4bffa17d39a62bd6d7c57db17850e1f22788b8646f226554c95fd690ee8de75L20-R39) [[2]](diffhunk://#diff-e9a2087346a3cd1aba8abd540d01c2d10396a55b66935e8c03b59383251ab4f8L115-R116) [[3]](diffhunk://#diff-e7a4d56565aaa98f4c89dc3954e27233d4f5c480f180a86478a3901da6f90ae5R12) [[4]](diffhunk://#diff-e7a4d56565aaa98f4c89dc3954e27233d4f5c480f180a86478a3901da6f90ae5R31-R42) [[5]](diffhunk://#diff-e7a4d56565aaa98f4c89dc3954e27233d4f5c480f180a86478a3901da6f90ae5R54-R57) [[6]](diffhunk://#diff-0f28d0a272570d542dad8bd119415ae0363070a901540fc455e8b16f10e3c1a6R10) [[7]](diffhunk://#diff-0f28d0a272570d542dad8bd119415ae0363070a901540fc455e8b16f10e3c1a6R27-R38) [[8]](diffhunk://#diff-0f28d0a272570d542dad8bd119415ae0363070a901540fc455e8b16f10e3c1a6R52-R55) [[9]](diffhunk://#diff-f074b0fbd643127fd46c37085055bad34adf3b7d1b9d4d4fc7fe0851bef5fe50R8) [[10]](diffhunk://#diff-f074b0fbd643127fd46c37085055bad34adf3b7d1b9d4d4fc7fe0851bef5fe50R24-R35) [[11]](diffhunk://#diff-f074b0fbd643127fd46c37085055bad34adf3b7d1b9d4d4fc7fe0851bef5fe50R49-R52) * Updated API request type definitions to include the optional `capabilities` field (`ApiRequestTypes.ts`). [[1]](diffhunk://#diff-323a83bb10ebc94100586aadee937c29d77db9714dfed3e923894466976e5214R12) [[2]](diffhunk://#diff-323a83bb10ebc94100586aadee937c29d77db9714dfed3e923894466976e5214R44) [[3]](diffhunk://#diff-323a83bb10ebc94100586aadee937c29d77db9714dfed3e923894466976e5214R75) **Error Handling Improvements:** * Centralized the logic for determining if a redirect is required into the base error class (`AuthFlowErrorBase.ts`), removing redundant `isRedirectRequired` methods from specific error subclasses (`SignInError.ts`, `SignUpError.ts`, `ResetPasswordError.ts`). [[1]](diffhunk://#diff-d258b0a5af2cbf80110d814acf0b7df45e55bb0103bf53138e66020a93700a8bR152-R159) [[2]](diffhunk://#diff-9bd88fec8e83fbb9e1d8e770f5ddc0cc395bda13033c70c787b85970f8d80841L34-L41) [[3]](diffhunk://#diff-9bd88fec8e83fbb9e1d8e770f5ddc0cc395bda13033c70c787b85970f8d80841L78-R72) [[4]](diffhunk://#diff-ddccd76ab42f6c83000ec1e1857a6322d82dbf78b3e9d47c6fa07d4c0e9488bbL49-L56) [[5]](diffhunk://#diff-ddccd76ab42f6c83000ec1e1857a6322d82dbf78b3e9d47c6fa07d4c0e9488bbL79-R71) [[6]](diffhunk://#diff-6992ffb0801330c7612d8d2fd7b160539d6e05284428a22dbf784b72c651702dL56-L63) [[7]](diffhunk://#diff-6992ffb0801330c7612d8d2fd7b160539d6e05284428a22dbf784b72c651702dL76-L83) [[8]](diffhunk://#diff-6992ffb0801330c7612d8d2fd7b160539d6e05284428a22dbf784b72c651702dL94-L101) [[9]](diffhunk://#diff-6992ffb0801330c7612d8d2fd7b160539d6e05284428a22dbf784b72c651702dL120-R98) * Simplified resend code error classes for sign-in, sign-up, and reset password flows by removing unnecessary methods (`SignInResendCodeError`, `SignUpResendCodeError`, `ResetPasswordResendCodeError`). [[1]](diffhunk://#diff-9bd88fec8e83fbb9e1d8e770f5ddc0cc395bda13033c70c787b85970f8d80841L78-R72) [[2]](diffhunk://#diff-ddccd76ab42f6c83000ec1e1857a6322d82dbf78b3e9d47c6fa07d4c0e9488bbL79-R71) [[3]](diffhunk://#diff-6992ffb0801330c7612d8d2fd7b160539d6e05284428a22dbf784b72c651702dL120-R98) **Redirect Error Enhancements:** * Enhanced the `RedirectError` class to accept and display a more specific redirect reason from the server, improving error messaging (`CustomAuthApiError.ts`, `BaseApiClient.ts`). [[1]](diffhunk://#diff-2dd77566c3e5ea80a8842413c962e06065c43583c961afb159cda2b07e87c5ebL13-R17) [[2]](diffhunk://#diff-3a0d4ccac21db6d650f33cd543d93dd57d0505da0cc82a8cd38cfedbd5b3b55eL131-R134) **Other:** * Added a patch change file for backward compatibility support for `@azure/msal-browser`.
1 parent d8718bc commit ba6655b

File tree

17 files changed

+466
-91
lines changed

17 files changed

+466
-91
lines changed
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
{
2+
"type": "patch",
3+
"comment": "Backward compability support #7962",
4+
"packageName": "@azure/msal-browser",
5+
"email": "[email protected]",
6+
"dependentChangeType": "patch"
7+
}

lib/msal-browser/src/custom_auth/configuration/CustomAuthConfiguration.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ import {
1111
export type CustomAuthOptions = {
1212
challengeTypes?: Array<string>;
1313
authApiProxyUrl: string;
14+
capabilities?: Array<string>;
1415
};
1516

1617
export type CustomAuthConfiguration = Configuration & {

lib/msal-browser/src/custom_auth/controller/CustomAuthStandardController.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -112,7 +112,8 @@ export class CustomAuthStandardController
112112
new CustomAuthApiClient(
113113
this.authority.getCustomAuthApiDomain(),
114114
this.customAuthConfig.auth.clientId,
115-
new FetchHttpClient(this.logger)
115+
new FetchHttpClient(this.logger),
116+
this.customAuthConfig.customAuth?.capabilities?.join(" ")
116117
),
117118
this.authority
118119
);

lib/msal-browser/src/custom_auth/core/auth_flow/AuthFlowErrorBase.ts

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -149,4 +149,12 @@ export abstract class AuthActionErrorBase extends AuthFlowErrorBase {
149149
isTokenExpired(): boolean {
150150
return this.isTokenExpiredError();
151151
}
152+
153+
/**
154+
* Check if client app supports the challenge type configured in Entra.
155+
* @returns {boolean} True if client app doesn't support the challenge type configured in Entra, "loginPopup" function is required to continue the operation.
156+
*/
157+
isRedirectRequired(): boolean {
158+
return this.isRedirectError();
159+
}
152160
}

lib/msal-browser/src/custom_auth/core/error/CustomAuthApiError.ts

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,10 +10,11 @@ import { CustomAuthError } from "./CustomAuthError.js";
1010
* Error when no required authentication method by Microsoft Entra is supported
1111
*/
1212
export class RedirectError extends CustomAuthError {
13-
constructor(correlationId?: string) {
13+
constructor(correlationId?: string, public redirectReason?: string) {
1414
super(
1515
"redirect",
16-
"No required authentication method by Microsoft Entra is supported, a fallback to the web-based authentication flow is needed.",
16+
redirectReason ||
17+
"Redirect Error, a fallback to the browser-delegated authentication is needed. Use loginPopup instead.",
1718
correlationId
1819
);
1920
Object.setPrototypeOf(this, RedirectError.prototype);

lib/msal-browser/src/custom_auth/core/network_client/custom_auth_api/BaseApiClient.ts

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -128,7 +128,10 @@ export abstract class BaseApiClient {
128128
typeof responseData === "object" &&
129129
responseData.challenge_type === ChallengeType.REDIRECT
130130
) {
131-
throw new RedirectError(correlationId);
131+
throw new RedirectError(
132+
correlationId,
133+
responseData.redirect_reason
134+
);
132135
}
133136

134137
return {

lib/msal-browser/src/custom_auth/core/network_client/custom_auth_api/CustomAuthApiClient.ts

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -17,22 +17,26 @@ export class CustomAuthApiClient implements ICustomAuthApiClient {
1717
constructor(
1818
customAuthApiBaseUrl: string,
1919
clientId: string,
20-
httpClient: IHttpClient
20+
httpClient: IHttpClient,
21+
capabilities?: string
2122
) {
2223
this.signInApi = new SignInApiClient(
2324
customAuthApiBaseUrl,
2425
clientId,
25-
httpClient
26+
httpClient,
27+
capabilities
2628
);
2729
this.signUpApi = new SignupApiClient(
2830
customAuthApiBaseUrl,
2931
clientId,
30-
httpClient
32+
httpClient,
33+
capabilities
3134
);
3235
this.resetPasswordApi = new ResetPasswordApiClient(
3336
customAuthApiBaseUrl,
3437
clientId,
35-
httpClient
38+
httpClient,
39+
capabilities
3640
);
3741
}
3842
}

lib/msal-browser/src/custom_auth/core/network_client/custom_auth_api/ResetPasswordApiClient.ts

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ import {
99
} from "../../../CustomAuthConstants.js";
1010
import { CustomAuthApiError } from "../../error/CustomAuthApiError.js";
1111
import { BaseApiClient } from "./BaseApiClient.js";
12+
import { IHttpClient } from "../http_client/IHttpClient.js";
1213
import * as CustomAuthApiEndpoint from "./CustomAuthApiEndpoint.js";
1314
import * as CustomAuthApiErrorCode from "./types/ApiErrorCodes.js";
1415
import {
@@ -27,6 +28,18 @@ import {
2728
} from "./types/ApiResponseTypes.js";
2829

2930
export class ResetPasswordApiClient extends BaseApiClient {
31+
private readonly capabilities?: string;
32+
33+
constructor(
34+
customAuthApiBaseUrl: string,
35+
clientId: string,
36+
httpClient: IHttpClient,
37+
capabilities?: string
38+
) {
39+
super(customAuthApiBaseUrl, clientId, httpClient);
40+
this.capabilities = capabilities;
41+
}
42+
3043
/**
3144
* Start the password reset flow
3245
*/
@@ -38,6 +51,9 @@ export class ResetPasswordApiClient extends BaseApiClient {
3851
{
3952
challenge_type: params.challenge_type,
4053
username: params.username,
54+
...(this.capabilities && {
55+
capabilities: this.capabilities,
56+
}),
4157
},
4258
params.telemetryManager,
4359
params.correlationId

lib/msal-browser/src/custom_auth/core/network_client/custom_auth_api/SignInApiClient.ts

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ import { ServerTelemetryManager } from "@azure/msal-common/browser";
77
import { GrantType } from "../../../CustomAuthConstants.js";
88
import { CustomAuthApiError } from "../../error/CustomAuthApiError.js";
99
import { BaseApiClient } from "./BaseApiClient.js";
10+
import { IHttpClient } from "../http_client/IHttpClient.js";
1011
import * as CustomAuthApiEndpoint from "./CustomAuthApiEndpoint.js";
1112
import * as CustomAuthApiErrorCode from "./types/ApiErrorCodes.js";
1213
import {
@@ -23,6 +24,18 @@ import {
2324
} from "./types/ApiResponseTypes.js";
2425

2526
export class SignInApiClient extends BaseApiClient {
27+
private readonly capabilities?: string;
28+
29+
constructor(
30+
customAuthApiBaseUrl: string,
31+
clientId: string,
32+
httpClient: IHttpClient,
33+
capabilities?: string
34+
) {
35+
super(customAuthApiBaseUrl, clientId, httpClient);
36+
this.capabilities = capabilities;
37+
}
38+
2639
/**
2740
* Initiates the sign-in flow
2841
* @param username User's email
@@ -36,6 +49,9 @@ export class SignInApiClient extends BaseApiClient {
3649
{
3750
username: params.username,
3851
challenge_type: params.challenge_type,
52+
...(this.capabilities && {
53+
capabilities: this.capabilities,
54+
}),
3955
},
4056
params.telemetryManager,
4157
params.correlationId

lib/msal-browser/src/custom_auth/core/network_client/custom_auth_api/SignupApiClient.ts

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55

66
import { GrantType } from "../../../CustomAuthConstants.js";
77
import { BaseApiClient } from "./BaseApiClient.js";
8+
import { IHttpClient } from "../http_client/IHttpClient.js";
89
import * as CustomAuthApiEndpoint from "./CustomAuthApiEndpoint.js";
910
import {
1011
SignUpChallengeRequest,
@@ -20,6 +21,18 @@ import {
2021
} from "./types/ApiResponseTypes.js";
2122

2223
export class SignupApiClient extends BaseApiClient {
24+
private readonly capabilities?: string;
25+
26+
constructor(
27+
customAuthApiBaseUrl: string,
28+
clientId: string,
29+
httpClient: IHttpClient,
30+
capabilities?: string
31+
) {
32+
super(customAuthApiBaseUrl, clientId, httpClient);
33+
this.capabilities = capabilities;
34+
}
35+
2336
/**
2437
* Start the sign-up flow
2538
*/
@@ -33,6 +46,9 @@ export class SignupApiClient extends BaseApiClient {
3346
attributes: JSON.stringify(params.attributes),
3447
}),
3548
challenge_type: params.challenge_type,
49+
...(this.capabilities && {
50+
capabilities: this.capabilities,
51+
}),
3652
},
3753
params.telemetryManager,
3854
params.correlationId

0 commit comments

Comments
 (0)