@equinor/fusion-framework-module-msal-node 3.0.1 → 4.0.0

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 CHANGED
@@ -1,5 +1,29 @@
1
1
  # @equinor/fusion-framework-module-msal-node
2
2
 
3
+ ## 4.0.0
4
+
5
+ ### Major Changes
6
+
7
+ - abffa53: Major version bump for Fusion Framework React 19 release.
8
+
9
+ All packages are bumped to the next major version as part of the React 19 upgrade. This release drops support for React versions below 18 and includes breaking changes across the framework.
10
+
11
+ **Breaking changes:**
12
+ - Peer dependencies now require React 18 or 19 (`^18.0.0 || ^19.0.0`)
13
+ - React Router upgraded from v6 to v7
14
+ - Navigation module refactored with new history API
15
+ - `renderComponent` and `renderApp` now use `createRoot` API
16
+
17
+ **Migration:**
18
+ - Update your React version to 18.0.0 or higher before upgrading
19
+ - Replace `NavigationProvider.createRouter()` with `@equinor/fusion-framework-react-router`
20
+ - See individual package changelogs for package-specific migration steps
21
+
22
+ ### Patch Changes
23
+
24
+ - Updated dependencies [abffa53]
25
+ - @equinor/fusion-framework-module@6.0.0
26
+
3
27
  ## 3.0.1
4
28
 
5
29
  ### Patch Changes
@@ -49,7 +73,6 @@
49
73
  - [#3714](https://github.com/equinor/fusion-framework/pull/3714) [`11fe961`](https://github.com/equinor/fusion-framework/commit/11fe961794e4960ccb987bc320268cc9b263f1f8) Thanks [@odinr](https://github.com/odinr)! - Update AuthProvider interfaces to match MSAL v4 API format.
50
74
 
51
75
  This is a breaking change that updates the method signatures:
52
-
53
76
  - `login(options: { scopes: string[] })` → `login(options: { request: { scopes: string[] } })`
54
77
  - `acquireAccessToken(options: { scopes: string[]; interactive?: boolean })` → `acquireAccessToken(options: { request: { scopes: string[] }; interactive?: boolean })`
55
78
 
@@ -74,7 +97,6 @@
74
97
  - [#3674](https://github.com/equinor/fusion-framework/pull/3674) [`fe667d5`](https://github.com/equinor/fusion-framework/commit/fe667d54a8b9cb030ed7c2f2a6465c80b1b6b4f2) Thanks [@dependabot](https://github.com/apps/dependabot)! - Bump @azure/msal-node from 3.8.0 to 3.8.1
75
98
 
76
99
  ## Changes
77
-
78
100
  - Update AccountEntity.getAccountInfo method
79
101
  - Fixed minor type error in BaseManagedIdentitySource.ts
80
102
  - Improved Managed Identity JSDocs
@@ -107,7 +129,6 @@
107
129
  - [#3403](https://github.com/equinor/fusion-framework/pull/3403) [`2fff2ea`](https://github.com/equinor/fusion-framework/commit/2fff2ea1e4838627e297b7b401601f1186c95335) Thanks [@dependabot](https://github.com/apps/dependabot)! - chore: bump @azure/msal-node from 3.7.3 to 3.7.4
108
130
 
109
131
  ### Links
110
-
111
132
  - [GitHub releases](https://github.com/AzureAD/microsoft-authentication-library-for-js/releases/tag/msal-node-v3.7.4)
112
133
  - [npm changelog](https://www.npmjs.com/package/@azure/msal-node?activeTab=versions)
113
134
 
@@ -116,7 +137,6 @@
116
137
  ### Patch Changes
117
138
 
118
139
  - [#3209](https://github.com/equinor/fusion-framework/pull/3209) [`4215d80`](https://github.com/equinor/fusion-framework/commit/4215d80799d156a248feb0f195af370907332a33) Thanks [@dependabot](https://github.com/apps/dependabot)! - Updated open dependency from 10.1.2 to 10.2.0
119
-
120
140
  - Internal refactoring: replaced `is-wsl` dependency with `wsl-utils`
121
141
  - No breaking changes to public API
122
142
  - Improved WSL detection and compatibility
@@ -138,7 +158,6 @@
138
158
  ### Patch Changes
139
159
 
140
160
  - [#3343](https://github.com/equinor/fusion-framework/pull/3343) [`c1cd89a`](https://github.com/equinor/fusion-framework/commit/c1cd89abad4ca8f232a497316232d1f5ac8c530a) Thanks [@odinr](https://github.com/odinr)! - Comprehensive documentation overhaul with enhanced developer experience and platform-specific guidance.
141
-
142
161
  - **Complete README rewrite** with modern structure and comprehensive examples
143
162
  - **Added detailed API reference** with TypeScript interfaces and method documentation
144
163
  - **Enhanced authentication mode documentation** with clear use cases and examples
@@ -149,14 +168,12 @@
149
168
  - **Enhanced security documentation** explaining platform keychains and encryption
150
169
 
151
170
  **New Documentation:**
152
-
153
171
  - `docs/libsecret.md` - Platform-specific credential storage setup guide
154
172
  - Comprehensive Windows build tools installation instructions
155
173
  - Enhanced Linux libsecret installation for multiple distributions
156
174
  - macOS troubleshooting and setup guidance
157
175
 
158
176
  **Key Improvements:**
159
-
160
177
  - Clear separation between authentication modes with practical examples
161
178
  - Platform-specific installation and troubleshooting guidance
162
179
  - Better developer onboarding with quick start examples
@@ -176,7 +193,6 @@
176
193
  ### Major Changes
177
194
 
178
195
  - [#3075](https://github.com/equinor/fusion-framework/pull/3075) [`8fffbfb`](https://github.com/equinor/fusion-framework/commit/8fffbfb12daa9748bf5290e5084cd4d409aed253) Thanks [@odinr](https://github.com/odinr)! - This release makes `@equinor/fusion-framework-module-msal-node` an explicit ESM package by setting `type: "module"` in `package.json` and updating all internal TypeScript imports to use explicit `.js` extensions. This ensures compatibility with NodeNext module resolution and ESM environments, and aligns the runtime and published output with ESM standards.
179
-
180
196
  - All internal imports now use `.js` extensions (e.g., `import { X } from './foo.js'`)
181
197
  - `package.json` now explicitly sets `"type": "module"`
182
198
  - `tsconfig.json` updated to use `module` and `moduleResolution` set to `NodeNext`
@@ -210,18 +226,15 @@
210
226
  - [#3056](https://github.com/equinor/fusion-framework/pull/3056) [`378bade`](https://github.com/equinor/fusion-framework/commit/378bade86c38e1057afe125fffc0bb06d6927deb) Thanks [@odinr](https://github.com/odinr)! - Easily add secure Azure AD authentication to your Node.js Fusion Framework apps with the new `@equinor/fusion-framework-module-msal-node` package. This module is designed for developers who need to authenticate services, CLI tools, or background jobs against Microsoft Azure using familiar, robust MSAL flows—without the hassle of manual token management or insecure storage.
211
227
 
212
228
  **Why use this module?**
213
-
214
229
  - **Simple integration:** Plug into the Fusion Framework with minimal setup.
215
230
  - **Multiple auth flows:** Choose the right authentication mode for your use case—CI/CD, background jobs, or interactive CLI tools.
216
231
  - **Secure by default:** Tokens are encrypted and stored safely using `@azure/msal-node-extensions`.
217
232
  - **Consistent API:** Acquire tokens the same way across all your Node.js Fusion projects.
218
233
 
219
234
  **How to use:**
220
-
221
235
  1. Install the package in your Fusion Framework Node.js project.
222
236
  2. Enable the module and pick your authentication mode (`token_only`, `silent`, or `interactive`).
223
237
  3. Use the provided API to acquire tokens for Azure resources—no need to handle refresh logic or storage yourself.
224
-
225
238
  - Supports token_only, silent, and interactive authentication modes
226
239
  - Provides secure, encrypted token storage using `@azure/msal-node-extensions`
227
240
  - Integrates with Fusion Framework for seamless authentication
@@ -247,7 +260,7 @@
247
260
 
248
261
  const instance = await initialize();
249
262
  console.log(
250
- await instance.auth.acquireAccessToken({ scopes: ["user.read"] })
263
+ await instance.auth.acquireAccessToken({ scopes: ["user.read"] }),
251
264
  );
252
265
  ```
253
266
 
@@ -270,7 +283,7 @@
270
283
 
271
284
  const instance = await initialize();
272
285
  console.log(
273
- await instance.auth.acquireAccessToken({ scopes: ["user.read"] })
286
+ await instance.auth.acquireAccessToken({ scopes: ["user.read"] }),
274
287
  );
275
288
  ```
276
289
 
package/README.md CHANGED
@@ -1,13 +1,11 @@
1
- `@equinor/fusion-framework-module-msal-node` provides secure Azure AD authentication for Node.js applications using Microsoft's MSAL (Microsoft Authentication Library). Perfect for CLI tools, background services, and automated processes that need to authenticate with Microsoft services.
1
+ `@equinor/fusion-framework-module-msal-node` provides Azure AD authentication for Node.js applications using Microsoft's MSAL library. It targets CLI tools, background services, and automated pipelines that need to acquire Azure AD access tokens within the Fusion Framework module system.
2
2
 
3
3
  ## Features
4
4
 
5
- - **Multiple Authentication Modes**: Choose the right auth flow for your use case
6
- - **Secure Token Storage**: Encrypted credential storage using platform keychains
7
- - **Easy Integration**: Simple API that works seamlessly with Fusion Framework
8
- - **Token Management**: Automatic token refresh and caching
9
- - **Cross-Platform**: Works on Windows, macOS, and Linux
10
- - **Zero Configuration**: Sensible defaults with optional customization
5
+ - **Three authentication modes** interactive (browser login), silent (cached credentials), and token-only (static token passthrough)
6
+ - **Secure token storage** encrypted credential caching via platform keychains (Windows Credential Manager, macOS Keychain, Linux libsecret) using `@azure/msal-node-extensions`
7
+ - **Automatic token refresh** silent re-acquisition of cached tokens without user interaction
8
+ - **Fusion Framework integration** registers as the `auth` module and exposes `IAuthProvider` on the module instance
11
9
 
12
10
  ## Quick Start
13
11
 
@@ -23,192 +21,200 @@ const configurator = new ModulesConfigurator();
23
21
 
24
22
  enableAuthModule(configurator, (builder) => {
25
23
  builder.setMode('interactive');
26
- builder.setClientId('your-client-id');
27
- builder.setTenantId('your-tenant-id');
24
+ builder.setClientConfig('your-tenant-id', 'your-client-id');
25
+ builder.setServerPort(3000);
28
26
  });
29
27
 
30
- const framework = await initialize();
31
- const token = await framework.auth.acquireAccessToken({
32
- scopes: ['https://graph.microsoft.com/.default']
28
+ // After initialization the auth provider is available on the module instance
29
+ const token = await modules.auth.acquireAccessToken({
30
+ request: { scopes: ['https://graph.microsoft.com/.default'] },
33
31
  });
34
32
  ```
35
33
 
36
- ## Authentication Modes
37
-
38
- Choose the authentication mode that best fits your application's needs:
39
-
40
- | Mode | Description | Best For | User Interaction |
41
- |------|-------------|----------|------------------|
42
- | **`token_only`** | Uses a pre-provided access token | CI/CD pipelines, serverless functions | None |
43
- | **`silent`** | Uses cached credentials for background auth | Background services, scheduled tasks | None |
44
- | **`interactive`** | Browser-based login with local server | CLI tools, development, user-facing apps | Required |
45
-
46
- ### When to Use Each Mode
34
+ ## Architecture
47
35
 
48
- - **`token_only`**: When you already have a valid access token (e.g., from environment variables, CI/CD secrets)
49
- - **`silent`**: When you need background authentication without user interaction (e.g., scheduled jobs, background services)
50
- - **`interactive`**: When you need user login (e.g., CLI tools, development environments, user-facing applications)
36
+ The module registers under the name `auth` and produces an `IAuthProvider` instance during initialization. Which concrete provider class is created depends on the configured mode:
51
37
 
52
- ## Secure Token Storage
53
-
54
- The module uses `@azure/msal-node-extensions` for enterprise-grade security:
38
+ | Mode | Provider class | Behaviour |
39
+ |------|---------------|-----------|
40
+ | `interactive` | `AuthProviderInteractive` | Opens the default browser for OAuth 2.0 authorization code flow with PKCE, handled by a temporary local HTTP server |
41
+ | `silent` | `AuthProvider` | Acquires tokens silently from the MSAL cache; throws `NoAccountsError` if no cached session exists |
42
+ | `token_only` | `AuthTokenProvider` | Returns a static pre-supplied access token; login/logout are not supported |
55
43
 
56
- - **🔒 Platform Keychains**: Windows Credential Manager, macOS Keychain, Linux libsecret
57
- - **🔐 Encryption at Rest**: Tokens encrypted using platform-specific mechanisms
58
- - **🔄 Automatic Refresh**: Seamless token renewal without user intervention
59
- - **🌐 Cross-Platform**: Consistent security across Windows, macOS, and Linux
44
+ All three implement `IAuthProvider`, so consuming code can call `acquireAccessToken` regardless of mode.
60
45
 
61
- ## Usage Examples
46
+ ## Authentication Modes
62
47
 
63
- ### Token-Only Mode (CI/CD)
48
+ ### Interactive — browser-based login
64
49
 
65
- Perfect for automated processes where you already have a valid token:
50
+ Best for CLI tools, developer utilities, and any scenario requiring user sign-in.
66
51
 
67
52
  ```typescript
68
- import { enableAuthModule } from '@equinor/fusion-framework-module-msal-node';
69
- import { ModulesConfigurator } from '@equinor/fusion-framework-module';
70
-
71
- const configurator = new ModulesConfigurator();
72
-
73
53
  enableAuthModule(configurator, (builder) => {
74
- builder.setMode('token_only');
75
- builder.setAccessToken(process.env.ACCESS_TOKEN); // From CI/CD secrets
54
+ builder.setMode('interactive');
55
+ builder.setClientConfig('your-tenant-id', 'your-client-id');
56
+ builder.setServerPort(3000);
57
+ builder.setServerOnOpen((url) => {
58
+ console.log(`Open in browser: ${url}`);
59
+ });
76
60
  });
77
61
 
78
- const framework = await initialize();
79
- const token = await framework.auth.acquireAccessToken({
80
- scopes: ['https://graph.microsoft.com/.default']
62
+ // Login explicitly (opens browser)
63
+ const result = await modules.auth.login({
64
+ request: { scopes: ['https://graph.microsoft.com/.default'] },
81
65
  });
66
+ console.log('Logged in as', result.account?.username);
82
67
  ```
83
68
 
84
- ### Silent Mode (Background Services)
69
+ ### Silent cached credentials
85
70
 
86
- For background services that need to authenticate without user interaction:
71
+ Best for background services and scheduled tasks where a user has previously authenticated.
87
72
 
88
73
  ```typescript
89
- import { enableAuthModule } from '@equinor/fusion-framework-module-msal-node';
90
- import { ModulesConfigurator } from '@equinor/fusion-framework-module';
91
-
92
- const configurator = new ModulesConfigurator();
93
-
94
74
  enableAuthModule(configurator, (builder) => {
95
75
  builder.setMode('silent');
96
- builder.setClientId(process.env.AZURE_CLIENT_ID);
97
- builder.setTenantId(process.env.AZURE_TENANT_ID);
76
+ builder.setClientConfig(process.env.AZURE_TENANT_ID!, process.env.AZURE_CLIENT_ID!);
98
77
  });
99
78
 
100
- const framework = await initialize();
101
-
102
- // This will use cached credentials or fail if no valid cache exists
103
- try {
104
- const token = await framework.auth.acquireAccessToken({
105
- scopes: ['https://graph.microsoft.com/.default']
106
- });
107
- console.log('Authenticated successfully');
108
- } catch (error) {
109
- console.error('Silent authentication failed:', error.message);
110
- }
79
+ const token = await modules.auth.acquireAccessToken({
80
+ request: { scopes: ['https://graph.microsoft.com/.default'] },
81
+ });
111
82
  ```
112
83
 
113
- ### Interactive Mode (CLI Tools)
84
+ ### Token-only static token passthrough
114
85
 
115
- For CLI tools and development environments that require user login:
86
+ Best for CI/CD pipelines and automation where a token is provided externally.
116
87
 
117
88
  ```typescript
118
- import { enableAuthModule } from '@equinor/fusion-framework-module-msal-node';
119
- import { ModulesConfigurator } from '@equinor/fusion-framework-module';
120
-
121
- const configurator = new ModulesConfigurator();
122
-
123
89
  enableAuthModule(configurator, (builder) => {
124
- builder.setMode('interactive');
125
- builder.setClientId(process.env.AZURE_CLIENT_ID);
126
- builder.setTenantId(process.env.AZURE_TENANT_ID);
127
- builder.setServerPort(3000); // Optional: custom port
128
- builder.setServerOnOpen((url) => {
129
- console.log(`🌐 Please open your browser and navigate to: ${url}`);
130
- });
90
+ builder.setMode('token_only');
91
+ builder.setAccessToken(process.env.ACCESS_TOKEN!);
131
92
  });
132
93
 
133
- const framework = await initialize();
134
-
135
- // This will open a browser for user login
136
- const result = await framework.auth.login({
137
- scopes: ['https://graph.microsoft.com/.default']
94
+ const token = await modules.auth.acquireAccessToken({
95
+ request: { scopes: ['https://graph.microsoft.com/.default'] },
138
96
  });
139
- console.log('Login successful:', result.account?.username);
140
97
  ```
141
98
 
142
- ## Configuration
99
+ ## Secure Token Storage
143
100
 
144
- ### Required Settings
101
+ When using `setClientConfig`, the module creates a `PublicClientApplication` backed by an encrypted persistence cache from `@azure/msal-node-extensions`:
145
102
 
146
- | Setting | Description | Required For |
147
- |---------|-------------|--------------|
148
- | `clientId` | Azure AD application client ID | `silent`, `interactive` |
149
- | `tenantId` | Azure AD tenant ID | `silent`, `interactive` |
150
- | `accessToken` | Pre-obtained access token | `token_only` |
103
+ - **Platform keychains** Windows Credential Manager, macOS Keychain, Linux libsecret
104
+ - **Encryption at rest** — tokens encrypted using platform-specific mechanisms
105
+ - **User-scoped** cache files are scoped to the current OS user via `DataProtectionScope.CurrentUser`
151
106
 
152
- ### Optional Settings
107
+ The `libsecret` dependency is loaded lazily so environments that use `token_only` mode (such as CI runners) do not need it installed.
153
108
 
154
- | Setting | Description | Default | Mode |
155
- |---------|-------------|---------|------|
156
- | `serverPort` | Local server port for auth callbacks | `3000` | `interactive` |
157
- | `serverOnOpen` | Callback when browser opens | `undefined` | `interactive` |
109
+ ## Configuration Reference
158
110
 
159
- ### Environment Variables
111
+ ### `IAuthConfigurator` methods
160
112
 
161
- ```bash
162
- # Required for silent/interactive modes
163
- AZURE_CLIENT_ID=your-client-id
164
- AZURE_TENANT_ID=your-tenant-id
113
+ | Method | Description |
114
+ |--------|-------------|
115
+ | `setMode(mode)` | Set authentication mode: `'interactive'`, `'silent'`, or `'token_only'` |
116
+ | `setClientConfig(tenantId, clientId)` | Create an MSAL client with secure persistence cache |
117
+ | `setClient(client)` | Provide a pre-configured `PublicClientApplication` instance |
118
+ | `setAccessToken(token)` | Set a static access token (`token_only` mode) |
119
+ | `setServerPort(port)` | Set the local callback server port (`interactive` mode) |
120
+ | `setServerOnOpen(callback)` | Callback invoked with the login URL when the server is ready |
165
121
 
166
- # Required for token_only mode
167
- ACCESS_TOKEN=your-access-token
122
+ ### Required settings per mode
123
+
124
+ | Setting | `interactive` | `silent` | `token_only` |
125
+ |---------|:---:|:---:|:---:|
126
+ | `setClientConfig` or `setClient` | required | required | — |
127
+ | `setAccessToken` | — | — | required |
128
+ | `setServerPort` | required | — | — |
129
+
130
+ ## Error Handling
131
+
132
+ The module exports dedicated error classes from `@equinor/fusion-framework-module-msal-node/error`:
133
+
134
+ | Error | Thrown when |
135
+ |-------|-----------|
136
+ | `NoAccountsError` | Silent token acquisition finds no cached accounts |
137
+ | `SilentTokenAcquisitionError` | MSAL fails to acquire a token silently (expired session, network issue) |
138
+ | `AuthServerError` | The local callback server receives no authorization code or token exchange fails |
139
+ | `AuthServerTimeoutError` | The callback server times out (default 5 minutes) waiting for a browser response |
140
+
141
+ ```typescript
142
+ import { NoAccountsError } from '@equinor/fusion-framework-module-msal-node/error';
143
+
144
+ try {
145
+ const token = await modules.auth.acquireAccessToken({
146
+ request: { scopes: ['api://my-api/.default'] },
147
+ });
148
+ } catch (error) {
149
+ if (error instanceof NoAccountsError) {
150
+ console.error('No cached session — run interactive login first');
151
+ }
152
+ throw error;
153
+ }
168
154
  ```
169
155
 
170
156
  ## API Reference
171
157
 
172
158
  ### `enableAuthModule(configurator, configure)`
173
159
 
174
- Enables the MSAL Node module in your Fusion Framework application.
160
+ Registers the MSAL Node module with a Fusion Framework `ModulesConfigurator`.
175
161
 
176
- **Parameters:**
177
- - `configurator`: `ModulesConfigurator` - The modules configurator instance
178
- - `configure`: `(builder: IAuthConfigurator) => void` - Configuration function
162
+ - **configurator** — the `IModulesConfigurator` instance
163
+ - **configure** callback receiving an `IAuthConfigurator` builder
179
164
 
180
165
  ### `IAuthProvider`
181
166
 
182
- The authentication provider interface available at `framework.auth`:
167
+ Unified provider interface exposed as `modules.auth`:
183
168
 
184
169
  ```typescript
185
170
  interface IAuthProvider {
186
- // Acquire an access token for the specified scopes
187
- acquireAccessToken(options: {
188
- scopes: string[];
189
- interactive?: boolean
171
+ acquireAccessToken(options: {
172
+ request: { scopes: string[] };
173
+ interactive?: boolean;
190
174
  }): Promise<string>;
191
-
192
- // Login (interactive mode only)
193
- login(options: { scopes: string[] }): Promise<AuthenticationResult>;
194
-
195
- // Logout (interactive mode only)
175
+
176
+ login(options: { request: { scopes: string[] } }): Promise<AuthenticationResult>;
177
+
196
178
  logout(): Promise<void>;
197
179
  }
198
180
  ```
199
181
 
182
+ `login` and `logout` are only functional in interactive mode. In other modes they throw immediately.
183
+
200
184
 
201
185
  ## Troubleshooting
202
186
 
203
187
  ### Common Issues
204
188
 
205
- | Issue | Solution |
206
- |-------|----------|
207
- | **Invalid client/tenant ID** | Verify your Azure AD app registration settings |
208
- | **Port already in use** | Change the `serverPort` or kill the process using the port |
209
- | **Silent auth fails** | Ensure you've logged in interactively first to cache credentials |
210
- | **Token expired** | The module handles refresh automatically; check your scopes |
211
- | **Credential storage errors** | See our [credential storage guide](docs/libsecret.md) |
189
+ | Issue | Error Class | Solution |
190
+ |-------|------------|----------|
191
+ | **No cached session** | `NoAccountsError` | Run interactive login first to cache credentials, then retry with silent mode |
192
+ | **Silent auth fails** | `SilentTokenAcquisitionError` | Cached session may have expired or network is unavailable; fall back to interactive login |
193
+ | **Callback server fails** | `AuthServerError` | Check that the callback server port is not in use and the browser can reach it |
194
+ | **Callback server timeout** | `AuthServerTimeoutError` | The browser did not complete login within the timeout (default 5 min); retry or check network |
195
+ | **Invalid client/tenant ID** | | Verify your Azure AD app registration settings |
196
+ | **Port already in use** | — | Change the `serverPort` or kill the process using the port |
197
+ | **Token expired** | — | The module handles refresh automatically; check your scopes |
198
+ | **Credential storage errors** | — | See our [credential storage guide](docs/libsecret.md) |
199
+
200
+ All error classes are exported from `@equinor/fusion-framework-module-msal-node/error`. A common pattern is to attempt silent token acquisition first and fall back to interactive login on failure:
201
+
202
+ ```typescript
203
+ import { NoAccountsError, SilentTokenAcquisitionError } from '@equinor/fusion-framework-module-msal-node/error';
204
+
205
+ try {
206
+ const token = await modules.auth.acquireAccessToken({
207
+ request: { scopes: ['api://my-api/.default'] },
208
+ });
209
+ } catch (error) {
210
+ if (error instanceof NoAccountsError || error instanceof SilentTokenAcquisitionError) {
211
+ // Fall back to interactive login
212
+ await modules.auth.login({ request: { scopes: ['api://my-api/.default'] } });
213
+ } else {
214
+ throw error;
215
+ }
216
+ }
217
+ ```
212
218
 
213
219
  ### Getting Help
214
220
 
@@ -17,12 +17,34 @@ export class AuthConfigurator extends BaseConfigBuilder {
17
17
  super();
18
18
  this.setMode('interactive');
19
19
  }
20
+ /**
21
+ * Sets the authentication mode for the module.
22
+ *
23
+ * @param mode - The authentication mode: `'interactive'`, `'silent'`, or `'token_only'`.
24
+ */
20
25
  setMode(mode) {
21
26
  this._set('mode', mode);
22
27
  }
28
+ /**
29
+ * Sets a pre-configured MSAL `PublicClientApplication` instance.
30
+ *
31
+ * Use this when you need full control over the MSAL client configuration.
32
+ * For most cases, prefer {@link AuthConfigurator.setClientConfig | setClientConfig}.
33
+ *
34
+ * @param client - The MSAL `PublicClientApplication` instance.
35
+ */
23
36
  setClient(client) {
24
37
  this._set('client', client);
25
38
  }
39
+ /**
40
+ * Configures the MSAL client using Azure AD tenant and client IDs.
41
+ *
42
+ * Lazily creates a `PublicClientApplication` with a secure persistence cache.
43
+ * The dynamic import avoids requiring `libsecret` in environments that do not need it.
44
+ *
45
+ * @param tenantId - Azure AD tenant (directory) ID.
46
+ * @param clientId - Azure AD application (client) ID.
47
+ */
26
48
  setClientConfig(tenantId, clientId) {
27
49
  this._set('client', async () => {
28
50
  // Dynamically import the createAuthClient function since the client uses `libsecret``
@@ -32,12 +54,29 @@ export class AuthConfigurator extends BaseConfigBuilder {
32
54
  return createAuthClient(tenantId, clientId);
33
55
  });
34
56
  }
57
+ /**
58
+ * Sets the port for the local HTTP callback server used in interactive mode.
59
+ *
60
+ * @param port - Port number for the local server.
61
+ */
35
62
  setServerPort(port) {
36
63
  this._set('server.port', port);
37
64
  }
65
+ /**
66
+ * Sets a callback invoked when the login URL is ready in interactive mode.
67
+ *
68
+ * Use this to display or log the authentication URL for the user.
69
+ *
70
+ * @param onOpen - Callback receiving the authentication URL, or `undefined` to disable.
71
+ */
38
72
  setServerOnOpen(onOpen) {
39
73
  this._set('server.onOpen', onOpen);
40
74
  }
75
+ /**
76
+ * Sets a pre-obtained access token for `token_only` mode.
77
+ *
78
+ * @param token - The static access token string.
79
+ */
41
80
  setAccessToken(token) {
42
81
  this._set('accessToken', token);
43
82
  }
@@ -1 +1 @@
1
- {"version":3,"file":"AuthConfigurator.js","sourceRoot":"","sources":["../../src/AuthConfigurator.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"AuthConfigurator.js","sourceRoot":"","sources":["../../src/AuthConfigurator.ts"],"names":[],"mappings":"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"}
package/dist/esm/index.js CHANGED
@@ -1,3 +1,24 @@
1
+ /**
2
+ * `@equinor/fusion-framework-module-msal-node` provides Azure AD authentication
3
+ * for Node.js applications using Microsoft's MSAL library.
4
+ *
5
+ * Supports three authentication modes:
6
+ * - **interactive** — browser-based login with a local callback server (CLI tools, development)
7
+ * - **silent** — cached credential reuse without user interaction (background services)
8
+ * - **token_only** — static pre-obtained token passthrough (CI/CD, automation)
9
+ *
10
+ * @example
11
+ * ```typescript
12
+ * import { enableAuthModule } from '@equinor/fusion-framework-module-msal-node';
13
+ *
14
+ * enableAuthModule(configurator, (builder) => {
15
+ * builder.setMode('interactive');
16
+ * builder.setClientConfig('your-tenant-id', 'your-client-id');
17
+ * });
18
+ * ```
19
+ *
20
+ * @packageDocumentation
21
+ */
1
22
  export { AuthProvider } from './AuthProvider.js';
2
23
  export { module as authModule } from './module.js';
3
24
  export { enableModule as enableAuthModule } from './enable-module.js';
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,MAAM,mBAAmB,CAAC;AAMjD,OAAO,EAAE,MAAM,IAAI,UAAU,EAAuB,MAAM,aAAa,CAAC;AAExE,OAAO,EAAE,YAAY,IAAI,gBAAgB,EAAE,MAAM,oBAAoB,CAAC"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;GAoBG;AAEH,OAAO,EAAE,YAAY,EAAE,MAAM,mBAAmB,CAAC;AAMjD,OAAO,EAAE,MAAM,IAAI,UAAU,EAAuB,MAAM,aAAa,CAAC;AAExE,OAAO,EAAE,YAAY,IAAI,gBAAgB,EAAE,MAAM,oBAAoB,CAAC"}
@@ -1,3 +1,3 @@
1
1
  // Generated by genversion.
2
- export const version = '3.0.1';
2
+ export const version = '4.0.0';
3
3
  //# sourceMappingURL=version.js.map