@equinor/fusion-framework-module-msal 5.1.2 → 6.0.0-next.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +108 -0
- package/README.md +237 -40
- package/dist/esm/MsalClient.interface.js +2 -0
- package/dist/esm/MsalClient.interface.js.map +1 -0
- package/dist/esm/MsalClient.js +215 -0
- package/dist/esm/MsalClient.js.map +1 -0
- package/dist/esm/MsalConfigurator.js +248 -0
- package/dist/esm/MsalConfigurator.js.map +1 -0
- package/dist/esm/MsalProvider.interface.js +2 -0
- package/dist/esm/MsalProvider.interface.js.map +1 -0
- package/dist/esm/MsalProvider.js +525 -0
- package/dist/esm/MsalProvider.js.map +1 -0
- package/dist/esm/MsalProxyProvider.interface.js +2 -0
- package/dist/esm/MsalProxyProvider.interface.js.map +1 -0
- package/dist/esm/__tests__/versioning/resolve-version.test.js +29 -38
- package/dist/esm/__tests__/versioning/resolve-version.test.js.map +1 -1
- package/dist/esm/create-client-log-callback.js +87 -0
- package/dist/esm/create-client-log-callback.js.map +1 -0
- package/dist/esm/create-proxy-provider.js +84 -0
- package/dist/esm/create-proxy-provider.js.map +1 -0
- package/dist/esm/index.js +1 -1
- package/dist/esm/index.js.map +1 -1
- package/dist/esm/module.js +64 -16
- package/dist/esm/module.js.map +1 -1
- package/dist/esm/static.js +32 -2
- package/dist/esm/static.js.map +1 -1
- package/dist/esm/types.js +9 -0
- package/dist/esm/types.js.map +1 -1
- package/dist/esm/util/compare-origin.js +11 -0
- package/dist/esm/util/compare-origin.js.map +1 -0
- package/dist/esm/{v2/client/util/url.js → util/normalize-uri.js} +1 -10
- package/dist/esm/util/normalize-uri.js.map +1 -0
- package/dist/esm/{v2/client/util/browser.js → util/redirect.js} +1 -1
- package/dist/esm/util/redirect.js.map +1 -0
- package/dist/esm/v2/IAuthClient.interface.js +2 -0
- package/dist/esm/v2/IAuthClient.interface.js.map +1 -0
- package/dist/esm/v2/IPublicClientApplication.interface.js +2 -0
- package/dist/esm/v2/IPublicClientApplication.interface.js.map +1 -0
- package/dist/esm/v2/MsalProvider.interface.js +2 -0
- package/dist/esm/v2/MsalProvider.interface.js.map +1 -0
- package/dist/esm/v2/create-proxy-client.js +155 -0
- package/dist/esm/v2/create-proxy-client.js.map +1 -0
- package/dist/esm/v2/create-proxy-provider.js +140 -0
- package/dist/esm/v2/create-proxy-provider.js.map +1 -0
- package/dist/esm/v2/map-account-info.js +18 -0
- package/dist/esm/v2/map-account-info.js.map +1 -0
- package/dist/esm/v2/map-authentication-result.js +22 -0
- package/dist/esm/v2/map-authentication-result.js.map +1 -0
- package/dist/esm/version.js +1 -1
- package/dist/esm/version.js.map +1 -1
- package/dist/esm/versioning/resolve-version.js +28 -16
- package/dist/esm/versioning/resolve-version.js.map +1 -1
- package/dist/tsconfig.tsbuildinfo +1 -1
- package/dist/types/MsalClient.d.ts +141 -0
- package/dist/types/MsalClient.interface.d.ts +103 -0
- package/dist/types/MsalConfigurator.d.ts +147 -0
- package/dist/types/MsalProvider.d.ts +291 -0
- package/dist/types/MsalProvider.interface.d.ts +159 -0
- package/dist/types/MsalProxyProvider.interface.d.ts +52 -0
- package/dist/types/create-client-log-callback.d.ts +38 -0
- package/dist/types/create-proxy-provider.d.ts +19 -0
- package/dist/types/index.d.ts +5 -4
- package/dist/types/module.d.ts +70 -4
- package/dist/types/static.d.ts +32 -1
- package/dist/types/types.d.ts +14 -6
- package/dist/types/util/redirect.d.ts +1 -0
- package/dist/types/v2/IAuthClient.interface.d.ts +68 -0
- package/dist/types/v2/IPublicClientApplication.interface.d.ts +68 -0
- package/dist/types/v2/MsalProvider.interface.d.ts +85 -0
- package/dist/types/v2/create-proxy-client.d.ts +22 -0
- package/dist/types/v2/create-proxy-provider.d.ts +24 -0
- package/dist/types/v2/map-account-info.d.ts +9 -0
- package/dist/types/v2/map-authentication-result.d.ts +9 -0
- package/dist/types/v2/types.d.ts +12 -0
- package/dist/types/version.d.ts +1 -1
- package/dist/types/versioning/resolve-version.d.ts +1 -1
- package/package.json +11 -6
- package/src/MsalClient.interface.ts +121 -0
- package/src/MsalClient.ts +274 -0
- package/src/MsalConfigurator.ts +289 -0
- package/src/MsalProvider.interface.ts +175 -0
- package/src/MsalProvider.ts +597 -0
- package/src/MsalProxyProvider.interface.ts +71 -0
- package/src/__tests__/versioning/resolve-version.test.ts +29 -42
- package/src/create-client-log-callback.ts +101 -0
- package/src/create-proxy-provider.ts +89 -0
- package/src/index.ts +6 -7
- package/src/module.ts +88 -20
- package/src/static.ts +32 -3
- package/src/types.ts +15 -7
- package/src/util/compare-origin.ts +11 -0
- package/src/{v2/client/util/url.ts → util/normalize-uri.ts} +0 -10
- package/src/v2/IAuthClient.interface.ts +91 -0
- package/src/v2/IPublicClientApplication.interface.ts +71 -0
- package/src/v2/MsalProvider.interface.ts +92 -0
- package/src/v2/create-proxy-client.ts +186 -0
- package/src/v2/create-proxy-provider.ts +156 -0
- package/src/v2/map-account-info.ts +20 -0
- package/src/v2/map-authentication-result.ts +24 -0
- package/src/v2/types.ts +12 -0
- package/src/version.ts +1 -1
- package/src/versioning/resolve-version.ts +35 -28
- package/tsconfig.json +3 -0
- package/dist/esm/v2/client/behavior.js +0 -5
- package/dist/esm/v2/client/behavior.js.map +0 -1
- package/dist/esm/v2/client/client.js +0 -142
- package/dist/esm/v2/client/client.js.map +0 -1
- package/dist/esm/v2/client/create-auth-client.js +0 -36
- package/dist/esm/v2/client/create-auth-client.js.map +0 -1
- package/dist/esm/v2/client/index.js +0 -5
- package/dist/esm/v2/client/index.js.map +0 -1
- package/dist/esm/v2/client/log/console.js +0 -45
- package/dist/esm/v2/client/log/console.js.map +0 -1
- package/dist/esm/v2/client/request.js +0 -2
- package/dist/esm/v2/client/request.js.map +0 -1
- package/dist/esm/v2/client/util/browser.js.map +0 -1
- package/dist/esm/v2/client/util/url.js.map +0 -1
- package/dist/esm/v2/configurator.js +0 -42
- package/dist/esm/v2/configurator.js.map +0 -1
- package/dist/esm/v2/index.js +0 -3
- package/dist/esm/v2/index.js.map +0 -1
- package/dist/esm/v2/provider.js +0 -115
- package/dist/esm/v2/provider.js.map +0 -1
- package/dist/types/v2/client/behavior.d.ts +0 -13
- package/dist/types/v2/client/client.d.ts +0 -89
- package/dist/types/v2/client/create-auth-client.d.ts +0 -27
- package/dist/types/v2/client/index.d.ts +0 -5
- package/dist/types/v2/client/log/console.d.ts +0 -28
- package/dist/types/v2/client/request.d.ts +0 -65
- package/dist/types/v2/configurator.d.ts +0 -32
- package/dist/types/v2/index.d.ts +0 -2
- package/dist/types/v2/provider.d.ts +0 -59
- package/src/v2/client/behavior.ts +0 -14
- package/src/v2/client/client.ts +0 -180
- package/src/v2/client/create-auth-client.ts +0 -48
- package/src/v2/client/index.ts +0 -8
- package/src/v2/client/log/console.ts +0 -58
- package/src/v2/client/request.ts +0 -66
- package/src/v2/configurator.ts +0 -58
- package/src/v2/index.ts +0 -2
- package/src/v2/provider.ts +0 -178
- /package/dist/types/{v2/client/util/browser.d.ts → util/compare-origin.d.ts} +0 -0
- /package/dist/types/{v2/client/util/url.d.ts → util/normalize-uri.d.ts} +0 -0
- /package/src/{v2/client/util/browser.ts → util/redirect.ts} +0 -0
|
@@ -1,17 +1,12 @@
|
|
|
1
1
|
import { describe, it, expect, vi } from 'vitest';
|
|
2
2
|
import { SemVer } from 'semver';
|
|
3
|
-
import { resolveVersion } from '../../versioning/resolve-version';
|
|
4
3
|
|
|
5
|
-
// Mock the
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
MsalModuleVersion: {
|
|
9
|
-
V2: 'v2',
|
|
10
|
-
Latest: '4.0.9', // Fixed version for consistent testing
|
|
11
|
-
},
|
|
4
|
+
// Mock the version first (hoisted)
|
|
5
|
+
vi.mock('../../version', () => ({
|
|
6
|
+
version: '6.1.2-next.0+1493919587',
|
|
12
7
|
}));
|
|
13
8
|
|
|
14
|
-
|
|
9
|
+
import { resolveVersion } from '../../versioning/resolve-version';
|
|
15
10
|
import { MsalModuleVersion } from '../../static';
|
|
16
11
|
|
|
17
12
|
describe('resolveVersion', () => {
|
|
@@ -23,12 +18,12 @@ describe('resolveVersion', () => {
|
|
|
23
18
|
wantedVersion: expect.any(SemVer),
|
|
24
19
|
latestVersion: expect.any(SemVer),
|
|
25
20
|
isLatest: false,
|
|
26
|
-
satisfiesLatest: false, // 2.x is not compatible with
|
|
21
|
+
satisfiesLatest: false, // 2.x is not compatible with 5.x
|
|
27
22
|
enumVersion: MsalModuleVersion.V2,
|
|
28
23
|
});
|
|
29
24
|
|
|
30
25
|
expect(result.wantedVersion.version).toBe('2.1.0');
|
|
31
|
-
expect(result.latestVersion.version).toBe('
|
|
26
|
+
expect(result.latestVersion.version).toBe('6.1.2');
|
|
32
27
|
});
|
|
33
28
|
|
|
34
29
|
it('should resolve with SemVer object', () => {
|
|
@@ -36,14 +31,14 @@ describe('resolveVersion', () => {
|
|
|
36
31
|
const result = resolveVersion(semver);
|
|
37
32
|
|
|
38
33
|
expect(result.wantedVersion).toBe(semver);
|
|
39
|
-
expect(result.satisfiesLatest).toBe(false); // 2.x is not compatible with
|
|
34
|
+
expect(result.satisfiesLatest).toBe(false); // 2.x is not compatible with 5.x
|
|
40
35
|
});
|
|
41
36
|
|
|
42
37
|
it('should resolve latest version when no version provided', () => {
|
|
43
38
|
const result = resolveVersion();
|
|
44
39
|
|
|
45
|
-
expect(result.wantedVersion.version).toBe('
|
|
46
|
-
expect(result.latestVersion.version).toBe('
|
|
40
|
+
expect(result.wantedVersion.version).toBe('6.1.2');
|
|
41
|
+
expect(result.latestVersion.version).toBe('6.1.2');
|
|
47
42
|
expect(result.isLatest).toBe(true);
|
|
48
43
|
expect(result.satisfiesLatest).toBe(true);
|
|
49
44
|
});
|
|
@@ -51,7 +46,7 @@ describe('resolveVersion', () => {
|
|
|
51
46
|
it('should resolve latest version when empty string provided', () => {
|
|
52
47
|
const result = resolveVersion('');
|
|
53
48
|
|
|
54
|
-
expect(result.wantedVersion.version).toBe('
|
|
49
|
+
expect(result.wantedVersion.version).toBe('6.1.2');
|
|
55
50
|
expect(result.isLatest).toBe(true);
|
|
56
51
|
});
|
|
57
52
|
|
|
@@ -59,54 +54,46 @@ describe('resolveVersion', () => {
|
|
|
59
54
|
const result = resolveVersion('2.5.0');
|
|
60
55
|
|
|
61
56
|
expect(result.enumVersion).toBe(MsalModuleVersion.V2);
|
|
62
|
-
expect(result.satisfiesLatest).toBe(false); // 2.x is not compatible with
|
|
57
|
+
expect(result.satisfiesLatest).toBe(false); // 2.x is not compatible with 5.x
|
|
63
58
|
});
|
|
64
59
|
});
|
|
65
60
|
|
|
66
61
|
describe('version comparison and warnings', () => {
|
|
67
62
|
it('should identify version states correctly', () => {
|
|
68
63
|
// Exact latest version
|
|
69
|
-
expect(resolveVersion('
|
|
64
|
+
expect(resolveVersion('6.1.2-next.0+1493919587').isLatest).toBe(true);
|
|
70
65
|
|
|
71
66
|
// Patch difference (satisfies but not latest)
|
|
72
|
-
const patchResult = resolveVersion('
|
|
67
|
+
const patchResult = resolveVersion('6.1.1');
|
|
73
68
|
expect(patchResult.isLatest).toBe(false);
|
|
74
69
|
expect(patchResult.satisfiesLatest).toBe(true);
|
|
75
70
|
expect(patchResult.warnings).toBeUndefined();
|
|
76
71
|
|
|
77
|
-
// Minor difference (satisfies
|
|
78
|
-
const minorResult = resolveVersion('
|
|
72
|
+
// Minor difference (satisfies)
|
|
73
|
+
const minorResult = resolveVersion('6.0.0');
|
|
79
74
|
expect(minorResult.isLatest).toBe(false);
|
|
80
75
|
expect(minorResult.satisfiesLatest).toBe(true);
|
|
81
|
-
expect(minorResult.warnings).toBeDefined();
|
|
82
|
-
expect(minorResult.warnings?.[0]).toContain(
|
|
83
|
-
'Requested minor version 1 is different from the latest minor version 0',
|
|
84
|
-
);
|
|
85
76
|
|
|
86
|
-
// Major difference (doesn't satisfy
|
|
87
|
-
const majorResult = resolveVersion('
|
|
77
|
+
// Major difference (doesn't satisfy)
|
|
78
|
+
const majorResult = resolveVersion('7.0.0');
|
|
88
79
|
expect(majorResult.satisfiesLatest).toBe(false);
|
|
89
|
-
expect(majorResult.warnings).toBeDefined();
|
|
90
|
-
expect(majorResult.warnings?.[0]).toContain(
|
|
91
|
-
'Requested major version 5 is greater than the latest major version 4',
|
|
92
|
-
);
|
|
93
80
|
});
|
|
94
81
|
|
|
95
82
|
it('should handle versions without matching enum with warnings', () => {
|
|
96
|
-
// Lower major version
|
|
83
|
+
// Lower major version - should map to V2
|
|
97
84
|
const lowerResult = resolveVersion('3.0.0');
|
|
98
|
-
expect(lowerResult.enumVersion).toBe(
|
|
85
|
+
expect(lowerResult.enumVersion).toBe(MsalModuleVersion.V2);
|
|
99
86
|
expect(lowerResult.warnings).toBeDefined();
|
|
100
87
|
expect(lowerResult.warnings?.[0]).toContain(
|
|
101
|
-
'Requested major version 3 is behind the latest major version
|
|
88
|
+
'Requested major version 3 is behind the latest major version 6',
|
|
102
89
|
);
|
|
103
90
|
|
|
104
|
-
// Zero version
|
|
91
|
+
// Zero version - should map to V2
|
|
105
92
|
const zeroResult = resolveVersion('0.0.0');
|
|
106
|
-
expect(zeroResult.enumVersion).toBe(
|
|
93
|
+
expect(zeroResult.enumVersion).toBe(MsalModuleVersion.V2);
|
|
107
94
|
expect(zeroResult.warnings).toBeDefined();
|
|
108
95
|
expect(zeroResult.warnings?.[0]).toContain(
|
|
109
|
-
'Requested major version 0 is behind the latest major version
|
|
96
|
+
'Requested major version 0 is behind the latest major version 6',
|
|
110
97
|
);
|
|
111
98
|
});
|
|
112
99
|
});
|
|
@@ -122,8 +109,8 @@ describe('resolveVersion', () => {
|
|
|
122
109
|
expect(result.warnings?.[0]).toContain(
|
|
123
110
|
`Failed to parse requested version "${invalidVersion}"`,
|
|
124
111
|
);
|
|
125
|
-
// Should fall back to latest version
|
|
126
|
-
expect(result.wantedVersion.version).toBe('
|
|
112
|
+
// Should fall back to latest version (coerced)
|
|
113
|
+
expect(result.wantedVersion.version).toBe('6.1.2');
|
|
127
114
|
});
|
|
128
115
|
});
|
|
129
116
|
|
|
@@ -137,9 +124,9 @@ describe('resolveVersion', () => {
|
|
|
137
124
|
describe('edge cases', () => {
|
|
138
125
|
it('should handle complex version strings with pre-release and build metadata', () => {
|
|
139
126
|
const testCases = [
|
|
140
|
-
{ input: '
|
|
141
|
-
{ input: '
|
|
142
|
-
{ input: '
|
|
127
|
+
{ input: '6.1.2-next.0+1493919587-beta.1', expected: '6.1.2' },
|
|
128
|
+
{ input: '6.1.2-next.0+1493919587+build.123', expected: '6.1.2' },
|
|
129
|
+
{ input: '6.1.2-next.0+1493919587-beta.1.alpha.2+build.123.456', expected: '6.1.2' },
|
|
143
130
|
];
|
|
144
131
|
|
|
145
132
|
testCases.forEach(({ input, expected }) => {
|
|
@@ -155,7 +142,7 @@ describe('resolveVersion', () => {
|
|
|
155
142
|
|
|
156
143
|
// Latest version should be consistent
|
|
157
144
|
expect(result1.latestVersion.version).toBe(result2.latestVersion.version);
|
|
158
|
-
expect(result1.latestVersion.version).toBe('
|
|
145
|
+
expect(result1.latestVersion.version).toBe('6.1.2');
|
|
159
146
|
|
|
160
147
|
// Structure should be consistent
|
|
161
148
|
expect(result1).toHaveProperty('wantedVersion');
|
|
@@ -0,0 +1,101 @@
|
|
|
1
|
+
import { type ILoggerCallback, LogLevel } from '@azure/msal-browser';
|
|
2
|
+
import {
|
|
3
|
+
type ITelemetryProvider,
|
|
4
|
+
TelemetryLevel,
|
|
5
|
+
} from '@equinor/fusion-framework-module-telemetry';
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* Maps MSAL log levels to corresponding telemetry levels.
|
|
9
|
+
*
|
|
10
|
+
* This mapping ensures consistent log level translation between MSAL's logging
|
|
11
|
+
* system and the framework's telemetry system.
|
|
12
|
+
*/
|
|
13
|
+
const levelMap: Partial<Record<LogLevel, TelemetryLevel>> = {
|
|
14
|
+
[LogLevel.Verbose]: TelemetryLevel.Debug,
|
|
15
|
+
[LogLevel.Info]: TelemetryLevel.Information,
|
|
16
|
+
[LogLevel.Warning]: TelemetryLevel.Warning,
|
|
17
|
+
[LogLevel.Error]: TelemetryLevel.Error,
|
|
18
|
+
};
|
|
19
|
+
|
|
20
|
+
/**
|
|
21
|
+
* Parses MSAL log message into structured components.
|
|
22
|
+
*
|
|
23
|
+
* MSAL log messages follow the format:
|
|
24
|
+
* [timestamp] : [correlationId] : [package] : [level] - [component] - [message]
|
|
25
|
+
*
|
|
26
|
+
* @param message - Raw MSAL log message
|
|
27
|
+
* @returns Parsed message components
|
|
28
|
+
*/
|
|
29
|
+
const parseMsalMessage = (message: string) => {
|
|
30
|
+
// Match the structured format: [timestamp] : [correlationId] : [package] : [level] - [component] - [message]
|
|
31
|
+
const match = message.match(
|
|
32
|
+
/^\[([^\]]+)\]\s*:\s*\[([^\]]*)\]\s*:\s*([^:]+)\s*:\s*(\w+)\s*-\s*([^-]+)\s*-\s*(.*)$/,
|
|
33
|
+
);
|
|
34
|
+
|
|
35
|
+
if (match) {
|
|
36
|
+
const [, _timestamp, _correlationId, packageInfo, _logLevel, component, logMessage] = match;
|
|
37
|
+
return {
|
|
38
|
+
package: packageInfo.trim() ?? undefined,
|
|
39
|
+
component: component.trim() ?? undefined,
|
|
40
|
+
message: logMessage.trim() ?? undefined,
|
|
41
|
+
};
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
// Fallback for non-structured messages
|
|
45
|
+
return { message: message.trim() };
|
|
46
|
+
};
|
|
47
|
+
|
|
48
|
+
/**
|
|
49
|
+
* Creates a telemetry callback function for MSAL logging integration.
|
|
50
|
+
*
|
|
51
|
+
* This function bridges MSAL's internal logging system with the framework's
|
|
52
|
+
* telemetry infrastructure. It maps MSAL log levels to telemetry levels and
|
|
53
|
+
* forwards log events to the provided telemetry provider with structured metadata.
|
|
54
|
+
*
|
|
55
|
+
* The callback function returned by this method will be called by MSAL whenever
|
|
56
|
+
* a log event occurs, allowing for centralized logging and monitoring of
|
|
57
|
+
* authentication-related events.
|
|
58
|
+
*
|
|
59
|
+
* @param provider - Telemetry provider instance to receive log events
|
|
60
|
+
* @param metadata - Additional metadata to include with each telemetry event (e.g., module version, environment)
|
|
61
|
+
* @param scope - Telemetry scope identifiers for categorization and filtering
|
|
62
|
+
* @returns Logger callback function for MSAL that forwards events to telemetry provider
|
|
63
|
+
*
|
|
64
|
+
* @example
|
|
65
|
+
* ```typescript
|
|
66
|
+
* const callback = createClientLogCallback(
|
|
67
|
+
* telemetryProvider,
|
|
68
|
+
* { module: 'msal', version: '4.0.0' },
|
|
69
|
+
* ['framework', 'authentication']
|
|
70
|
+
* );
|
|
71
|
+
*
|
|
72
|
+
* // Use with MSAL configuration
|
|
73
|
+
* const config = {
|
|
74
|
+
* system: {
|
|
75
|
+
* loggerOptions: {
|
|
76
|
+
* loggerCallback: callback,
|
|
77
|
+
* piiLoggingEnabled: false
|
|
78
|
+
* }
|
|
79
|
+
* }
|
|
80
|
+
* };
|
|
81
|
+
* ```
|
|
82
|
+
*/
|
|
83
|
+
export const createClientLogCallback = (
|
|
84
|
+
provider: ITelemetryProvider,
|
|
85
|
+
metadata: Record<string, unknown>,
|
|
86
|
+
scope: string[],
|
|
87
|
+
): ILoggerCallback | undefined => {
|
|
88
|
+
return (level: LogLevel, message: string, _containsPii: boolean) => {
|
|
89
|
+
const parsedMessage = parseMsalMessage(message);
|
|
90
|
+
|
|
91
|
+
provider.trackEvent({
|
|
92
|
+
name: 'MsalClient',
|
|
93
|
+
level: levelMap[level] ?? TelemetryLevel.Information,
|
|
94
|
+
scope,
|
|
95
|
+
metadata,
|
|
96
|
+
properties: {
|
|
97
|
+
...parsedMessage,
|
|
98
|
+
},
|
|
99
|
+
});
|
|
100
|
+
};
|
|
101
|
+
};
|
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
import type { IMsalProvider } from './MsalProvider.interface';
|
|
2
|
+
import { MsalModuleVersion } from './static';
|
|
3
|
+
import { resolveVersion } from './versioning/resolve-version';
|
|
4
|
+
import { createProxyProvider as createProxyProvider_v2 } from './v2/create-proxy-provider';
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* Creates a proxy provider for version compatibility.
|
|
8
|
+
*
|
|
9
|
+
* This function handles the creation of proxy providers that maintain
|
|
10
|
+
* backward compatibility with different MSAL versions while using the
|
|
11
|
+
* latest MSAL v4 implementation under the hood.
|
|
12
|
+
*
|
|
13
|
+
* @param provider - The base MSAL provider instance
|
|
14
|
+
* @param version - The target version string (e.g., '2.0.0', '4.0.0')
|
|
15
|
+
* @returns A proxy provider compatible with the specified version
|
|
16
|
+
*
|
|
17
|
+
* @example
|
|
18
|
+
* ```typescript
|
|
19
|
+
* const baseProvider = new MsalProvider(config);
|
|
20
|
+
* const v2Proxy = createProxyProvider(baseProvider, '2.0.0');
|
|
21
|
+
* ```
|
|
22
|
+
*/
|
|
23
|
+
export function createProxyProvider<T = IMsalProvider>(
|
|
24
|
+
provider: IMsalProvider,
|
|
25
|
+
version: string,
|
|
26
|
+
): T {
|
|
27
|
+
// Resolve the requested version to determine which proxy to create
|
|
28
|
+
const { enumVersion } = resolveVersion(version);
|
|
29
|
+
|
|
30
|
+
switch (enumVersion) {
|
|
31
|
+
case MsalModuleVersion.V2:
|
|
32
|
+
// Create v2-compatible proxy with legacy API adapters
|
|
33
|
+
return createProxyProvider_v2(provider) as T;
|
|
34
|
+
case MsalModuleVersion.V4:
|
|
35
|
+
// Create transparent proxy for v4 - passes through to original provider
|
|
36
|
+
// This allows v4 code to be used where any version is expected
|
|
37
|
+
return new Proxy(provider, {
|
|
38
|
+
get: (target: IMsalProvider, prop: keyof IMsalProvider) => {
|
|
39
|
+
switch (prop) {
|
|
40
|
+
case 'version': {
|
|
41
|
+
return target.version;
|
|
42
|
+
}
|
|
43
|
+
case 'msalVersion': {
|
|
44
|
+
return enumVersion;
|
|
45
|
+
}
|
|
46
|
+
case 'client': {
|
|
47
|
+
return target.client;
|
|
48
|
+
}
|
|
49
|
+
case 'account': {
|
|
50
|
+
return target.account;
|
|
51
|
+
}
|
|
52
|
+
case 'acquireAccessToken': {
|
|
53
|
+
return target.acquireAccessToken.bind(target);
|
|
54
|
+
}
|
|
55
|
+
case 'acquireToken': {
|
|
56
|
+
return target.acquireToken.bind(target);
|
|
57
|
+
}
|
|
58
|
+
case 'login': {
|
|
59
|
+
return target.login.bind(target);
|
|
60
|
+
}
|
|
61
|
+
case 'logout': {
|
|
62
|
+
return target.logout.bind(target);
|
|
63
|
+
}
|
|
64
|
+
case 'handleRedirect': {
|
|
65
|
+
return target.handleRedirect.bind(target);
|
|
66
|
+
}
|
|
67
|
+
case 'createProxyProvider': {
|
|
68
|
+
return target.createProxyProvider.bind(target);
|
|
69
|
+
}
|
|
70
|
+
case 'initialize': {
|
|
71
|
+
return () => {
|
|
72
|
+
// noop - initialize is handled by the provider, not the proxy
|
|
73
|
+
};
|
|
74
|
+
}
|
|
75
|
+
default: {
|
|
76
|
+
// backstop to prevent then from being called - this is not an async operation
|
|
77
|
+
if (prop === 'then') return undefined;
|
|
78
|
+
|
|
79
|
+
// Exhaustive check: TypeScript-only guard to ensure all IMsalProvider keys are handled
|
|
80
|
+
const exhausted: never = prop;
|
|
81
|
+
return (target as IMsalProvider)[exhausted];
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
},
|
|
85
|
+
}) as T;
|
|
86
|
+
default:
|
|
87
|
+
throw new Error(`Version ${version} is not supported`);
|
|
88
|
+
}
|
|
89
|
+
}
|
package/src/index.ts
CHANGED
|
@@ -2,15 +2,14 @@ export {
|
|
|
2
2
|
module,
|
|
3
3
|
configureMsal,
|
|
4
4
|
enableMSAL,
|
|
5
|
-
type AuthConfigurator as IAppConfigurator,
|
|
6
|
-
type AuthConfigFn,
|
|
7
|
-
type IAuthProvider,
|
|
8
5
|
type MsalModule,
|
|
6
|
+
type AuthConfigFn,
|
|
9
7
|
} from './module';
|
|
10
8
|
|
|
11
|
-
export {
|
|
9
|
+
export type { IMsalProvider } from './MsalProvider.interface';
|
|
10
|
+
export type { IMsalClient } from './MsalClient.interface';
|
|
11
|
+
export { MsalClient, type MsalClientConfig } from './MsalClient';
|
|
12
12
|
|
|
13
|
-
export {
|
|
13
|
+
export type { AccountInfo, AuthenticationResult } from './types';
|
|
14
14
|
|
|
15
|
-
export
|
|
16
|
-
export type { AuthClientConfig } from './v2/configurator';
|
|
15
|
+
export { default } from './module';
|
package/src/module.ts
CHANGED
|
@@ -4,62 +4,116 @@ import {
|
|
|
4
4
|
SemanticVersion,
|
|
5
5
|
} from '@equinor/fusion-framework-module';
|
|
6
6
|
|
|
7
|
-
import {
|
|
7
|
+
import { MsalConfigurator } from './MsalConfigurator';
|
|
8
|
+
import { MsalProvider, type IMsalProvider } from './MsalProvider';
|
|
9
|
+
import type { MsalClientConfig } from './MsalClient';
|
|
8
10
|
|
|
9
|
-
import {
|
|
11
|
+
import { version } from './version';
|
|
10
12
|
|
|
11
|
-
|
|
12
|
-
|
|
13
|
+
/**
|
|
14
|
+
* MSAL authentication module configuration.
|
|
15
|
+
*
|
|
16
|
+
* This module provides Microsoft Authentication Library (MSAL) integration for the
|
|
17
|
+
* Fusion Framework, supporting MSAL v4 with backward compatibility for v2 applications.
|
|
18
|
+
*/
|
|
19
|
+
export type MsalModule = Module<'auth', IMsalProvider, MsalConfigurator, [MsalModule]>;
|
|
13
20
|
|
|
21
|
+
/**
|
|
22
|
+
* MSAL authentication module definition.
|
|
23
|
+
*
|
|
24
|
+
* This module manages authentication providers with the following initialization flow:
|
|
25
|
+
* 1. Check for custom provider configuration
|
|
26
|
+
* 2. Check for existing provider in parent module (for proxy compatibility)
|
|
27
|
+
* 3. Create new provider with client configuration
|
|
28
|
+
*
|
|
29
|
+
* @remarks
|
|
30
|
+
* The module supports proxy providers for version compatibility, allowing v4 implementations
|
|
31
|
+
* to work with v2-compatible code during migration periods.
|
|
32
|
+
*/
|
|
14
33
|
export const module: MsalModule = {
|
|
15
34
|
name: 'auth',
|
|
16
|
-
version: new SemanticVersion(
|
|
17
|
-
configure: () => new
|
|
35
|
+
version: new SemanticVersion(version),
|
|
36
|
+
configure: () => new MsalConfigurator(),
|
|
18
37
|
initialize: async (init) => {
|
|
19
38
|
const config = await init.config.createConfigAsync(init);
|
|
20
39
|
|
|
21
|
-
//
|
|
40
|
+
// Priority 1: Use custom provider if explicitly configured
|
|
22
41
|
if (config.provider) {
|
|
23
42
|
return config.provider;
|
|
24
43
|
}
|
|
25
44
|
|
|
26
|
-
//
|
|
27
|
-
|
|
45
|
+
// Priority 2: Check if provider exists in parent module (proxy compatibility)
|
|
46
|
+
// This allows child applications to reuse parent's authentication provider
|
|
47
|
+
const hostProvider = init.ref?.auth;
|
|
28
48
|
if (hostProvider) {
|
|
29
49
|
try {
|
|
30
|
-
|
|
50
|
+
const proxyProvider = hostProvider.createProxyProvider(config.version);
|
|
51
|
+
return proxyProvider;
|
|
31
52
|
} catch (error) {
|
|
32
53
|
console.error('MsalModule::Failed to create proxy provider', error);
|
|
33
|
-
//
|
|
54
|
+
// Fallback to host provider to prevent app breakage during migration
|
|
55
|
+
// TODO: Consider throwing error instead once all apps are migrated to v4
|
|
34
56
|
return hostProvider;
|
|
35
57
|
}
|
|
36
58
|
}
|
|
37
59
|
|
|
60
|
+
// Priority 3: Validate client configuration is provided
|
|
38
61
|
if (!config.client) {
|
|
39
62
|
throw new Error(
|
|
40
63
|
'Client configuration is required when provider is not in the parent module nor defined',
|
|
41
64
|
);
|
|
42
65
|
}
|
|
43
66
|
|
|
44
|
-
//
|
|
45
|
-
const
|
|
67
|
+
// Create new MSAL provider instance
|
|
68
|
+
const provider = new MsalProvider(config);
|
|
46
69
|
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
await authProvider.login({ onlyIfRequired: true });
|
|
50
|
-
}
|
|
70
|
+
// Initialize the provider (handles redirect callbacks, SSO, etc.)
|
|
71
|
+
await provider.initialize();
|
|
51
72
|
|
|
52
|
-
return
|
|
73
|
+
return provider;
|
|
53
74
|
},
|
|
54
75
|
};
|
|
55
76
|
|
|
77
|
+
/**
|
|
78
|
+
* Configuration function type for MSAL module setup.
|
|
79
|
+
*
|
|
80
|
+
* This function receives a builder object with methods to configure the MSAL client
|
|
81
|
+
* and authentication requirements.
|
|
82
|
+
*/
|
|
56
83
|
export type AuthConfigFn = (builder: {
|
|
57
|
-
|
|
84
|
+
/**
|
|
85
|
+
* Set MSAL client configuration
|
|
86
|
+
* @param config - Client configuration with tenant ID, client ID, etc.
|
|
87
|
+
*/
|
|
88
|
+
setClientConfig: (config: MsalClientConfig) => void;
|
|
89
|
+
/**
|
|
90
|
+
* Set whether authentication is required for the application
|
|
91
|
+
* @param requiresAuth - If true, app will attempt automatic login on initialization
|
|
92
|
+
*/
|
|
58
93
|
setRequiresAuth: (requiresAuth: boolean) => void;
|
|
59
94
|
}) => void;
|
|
60
95
|
|
|
96
|
+
/**
|
|
97
|
+
* Enables MSAL authentication module in the framework.
|
|
98
|
+
*
|
|
99
|
+
* This is a convenience function that adds the MSAL module configuration to the
|
|
100
|
+
* framework configurator with optional configuration callback.
|
|
101
|
+
*
|
|
102
|
+
* @param configurator - The framework modules configurator instance
|
|
103
|
+
* @param configure - Optional configuration callback for MSAL setup
|
|
104
|
+
*
|
|
105
|
+
* @example
|
|
106
|
+
* ```typescript
|
|
107
|
+
* enableMSAL(frameworkConfigurator, (builder) => {
|
|
108
|
+
* builder.setClientConfig({
|
|
109
|
+
* auth: { clientId: 'your-client-id', tenantId: 'your-tenant-id' }
|
|
110
|
+
* });
|
|
111
|
+
* builder.setRequiresAuth(true);
|
|
112
|
+
* });
|
|
113
|
+
* ```
|
|
114
|
+
*/
|
|
61
115
|
export const enableMSAL = (
|
|
62
|
-
//
|
|
116
|
+
// @biome-ignore lint/suspicious/noExplicitAny: must be any to support all module types
|
|
63
117
|
configurator: IModulesConfigurator<any, any>,
|
|
64
118
|
configure?: AuthConfigFn,
|
|
65
119
|
): void => {
|
|
@@ -67,6 +121,20 @@ export const enableMSAL = (
|
|
|
67
121
|
configurator.addConfig(config);
|
|
68
122
|
};
|
|
69
123
|
|
|
124
|
+
/**
|
|
125
|
+
* Creates MSAL module configuration with custom setup.
|
|
126
|
+
*
|
|
127
|
+
* @param configure - Configuration callback function
|
|
128
|
+
* @returns Module configuration object ready for framework integration
|
|
129
|
+
*
|
|
130
|
+
* @example
|
|
131
|
+
* ```typescript
|
|
132
|
+
* const msalConfig = configureMsal((builder) => {
|
|
133
|
+
* builder.setClientConfig(msalClientConfig);
|
|
134
|
+
* builder.setRequiresAuth(true);
|
|
135
|
+
* });
|
|
136
|
+
* ```
|
|
137
|
+
*/
|
|
70
138
|
export const configureMsal = (configure: AuthConfigFn) => ({
|
|
71
139
|
module,
|
|
72
140
|
configure,
|
package/src/static.ts
CHANGED
|
@@ -1,8 +1,37 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
1
|
+
/**
|
|
2
|
+
* Module identifier for the MSAL authentication module.
|
|
3
|
+
*
|
|
4
|
+
* This constant is used to register and identify the MSAL module within the Fusion Framework.
|
|
5
|
+
*/
|
|
3
6
|
export const ModuleName = 'msal' as const;
|
|
4
7
|
|
|
8
|
+
/**
|
|
9
|
+
* Enumeration of supported MSAL module versions.
|
|
10
|
+
*
|
|
11
|
+
* This enum defines the available MSAL versions and provides type-safe access to version identifiers.
|
|
12
|
+
* The `Latest` value is automatically set to the current module version at build time.
|
|
13
|
+
*
|
|
14
|
+
* @remarks
|
|
15
|
+
* - `V2`: MSAL v2 compatibility (legacy support)
|
|
16
|
+
* - `V4`: MSAL v4 (current major version)
|
|
17
|
+
* - `Latest`: Always points to the current module version (5.1.0)
|
|
18
|
+
*
|
|
19
|
+
* @example
|
|
20
|
+
* ```typescript
|
|
21
|
+
* import { MsalModuleVersion } from '@equinor/fusion-framework-module-msal';
|
|
22
|
+
*
|
|
23
|
+
* // Check version
|
|
24
|
+
* if (version === MsalModuleVersion.Latest) {
|
|
25
|
+
* console.log('Using latest MSAL version');
|
|
26
|
+
* }
|
|
27
|
+
*
|
|
28
|
+
* // Create version-specific proxy
|
|
29
|
+
* const proxy = provider.createProxyProvider(MsalModuleVersion.V2);
|
|
30
|
+
* ```
|
|
31
|
+
*/
|
|
5
32
|
export enum MsalModuleVersion {
|
|
33
|
+
/** MSAL v2 compatibility version */
|
|
6
34
|
V2 = 'v2',
|
|
7
|
-
|
|
35
|
+
/** MSAL v4 (current major version) */
|
|
36
|
+
V4 = 'v4',
|
|
8
37
|
}
|
package/src/types.ts
CHANGED
|
@@ -1,8 +1,16 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
1
|
+
/**
|
|
2
|
+
* Re-exports of core MSAL types from @azure/msal-browser.
|
|
3
|
+
*
|
|
4
|
+
* This module provides convenient access to commonly used MSAL types without
|
|
5
|
+
* requiring direct imports from @azure/msal-browser. These types represent
|
|
6
|
+
* fundamental authentication entities used throughout the MSAL module.
|
|
7
|
+
*
|
|
8
|
+
* @module
|
|
9
|
+
*/
|
|
3
10
|
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
11
|
+
export {
|
|
12
|
+
/** Represents account information for an authenticated user */
|
|
13
|
+
AccountInfo,
|
|
14
|
+
/** Represents the result of an authentication operation including tokens and account */
|
|
15
|
+
AuthenticationResult,
|
|
16
|
+
} from '@azure/msal-browser';
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import { normalizeUri } from './normalize-uri';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Compares normalized version of urls
|
|
5
|
+
*
|
|
6
|
+
* @internal
|
|
7
|
+
*/
|
|
8
|
+
export const compareOrigin = (a: string, b: string): boolean => {
|
|
9
|
+
const url = { a: normalizeUri(a), b: normalizeUri(b) };
|
|
10
|
+
return url.a === url.b;
|
|
11
|
+
};
|
|
@@ -12,13 +12,3 @@ export const normalizeUri = (uri: string, home: string = window.location.origin)
|
|
|
12
12
|
const { origin, pathname } = new URL(uri);
|
|
13
13
|
return origin + pathname.replace(/([^:]\/)\/+/g, '$1');
|
|
14
14
|
};
|
|
15
|
-
|
|
16
|
-
/**
|
|
17
|
-
* Compares normalized version of urls
|
|
18
|
-
*
|
|
19
|
-
* @internal
|
|
20
|
-
*/
|
|
21
|
-
export const compareOrigin = (a: string, b: string): boolean => {
|
|
22
|
-
const url = { a: normalizeUri(a), b: normalizeUri(b) };
|
|
23
|
-
return url.a === url.b;
|
|
24
|
-
};
|