@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 +26 -13
- package/README.md +132 -126
- package/dist/esm/AuthConfigurator.js +39 -0
- package/dist/esm/AuthConfigurator.js.map +1 -1
- package/dist/esm/index.js +21 -0
- package/dist/esm/index.js.map +1 -1
- package/dist/esm/version.js +1 -1
- package/dist/tsconfig.tsbuildinfo +1 -1
- package/dist/types/AuthConfigurator.d.ts +39 -0
- package/dist/types/index.d.ts +21 -0
- package/dist/types/version.d.ts +1 -1
- package/package.json +3 -3
- package/src/AuthConfigurator.ts +39 -0
- package/src/index.ts +22 -0
- package/src/version.ts +1 -1
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
|
|
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
|
-
- **
|
|
6
|
-
- **Secure
|
|
7
|
-
- **
|
|
8
|
-
- **
|
|
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.
|
|
27
|
-
builder.
|
|
24
|
+
builder.setClientConfig('your-tenant-id', 'your-client-id');
|
|
25
|
+
builder.setServerPort(3000);
|
|
28
26
|
});
|
|
29
27
|
|
|
30
|
-
|
|
31
|
-
const token = await
|
|
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
|
-
##
|
|
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
|
-
|
|
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
|
-
|
|
53
|
-
|
|
54
|
-
|
|
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
|
-
|
|
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
|
-
##
|
|
46
|
+
## Authentication Modes
|
|
62
47
|
|
|
63
|
-
###
|
|
48
|
+
### Interactive — browser-based login
|
|
64
49
|
|
|
65
|
-
|
|
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('
|
|
75
|
-
builder.
|
|
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
|
-
|
|
79
|
-
const
|
|
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
|
|
69
|
+
### Silent — cached credentials
|
|
85
70
|
|
|
86
|
-
|
|
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.
|
|
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
|
|
101
|
-
|
|
102
|
-
|
|
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
|
-
###
|
|
84
|
+
### Token-only — static token passthrough
|
|
114
85
|
|
|
115
|
-
|
|
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('
|
|
125
|
-
builder.
|
|
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
|
|
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
|
-
##
|
|
99
|
+
## Secure Token Storage
|
|
143
100
|
|
|
144
|
-
|
|
101
|
+
When using `setClientConfig`, the module creates a `PublicClientApplication` backed by an encrypted persistence cache from `@azure/msal-node-extensions`:
|
|
145
102
|
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
###
|
|
111
|
+
### `IAuthConfigurator` methods
|
|
160
112
|
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
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
|
-
|
|
167
|
-
|
|
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
|
-
|
|
160
|
+
Registers the MSAL Node module with a Fusion Framework `ModulesConfigurator`.
|
|
175
161
|
|
|
176
|
-
**
|
|
177
|
-
-
|
|
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
|
-
|
|
167
|
+
Unified provider interface exposed as `modules.auth`:
|
|
183
168
|
|
|
184
169
|
```typescript
|
|
185
170
|
interface IAuthProvider {
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
interactive?: boolean
|
|
171
|
+
acquireAccessToken(options: {
|
|
172
|
+
request: { scopes: string[] };
|
|
173
|
+
interactive?: boolean;
|
|
190
174
|
}): Promise<string>;
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
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
|
-
| **
|
|
208
|
-
| **
|
|
209
|
-
| **
|
|
210
|
-
| **
|
|
211
|
-
| **
|
|
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';
|
package/dist/esm/index.js.map
CHANGED
|
@@ -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"}
|
package/dist/esm/version.js
CHANGED