@mcp-z/oauth-microsoft 1.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.
Files changed (89) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +98 -0
  3. package/dist/cjs/index.d.cts +16 -0
  4. package/dist/cjs/index.d.ts +16 -0
  5. package/dist/cjs/index.js +112 -0
  6. package/dist/cjs/index.js.map +1 -0
  7. package/dist/cjs/lib/dcr-router.d.cts +44 -0
  8. package/dist/cjs/lib/dcr-router.d.ts +44 -0
  9. package/dist/cjs/lib/dcr-router.js +1227 -0
  10. package/dist/cjs/lib/dcr-router.js.map +1 -0
  11. package/dist/cjs/lib/dcr-utils.d.cts +160 -0
  12. package/dist/cjs/lib/dcr-utils.d.ts +160 -0
  13. package/dist/cjs/lib/dcr-utils.js +860 -0
  14. package/dist/cjs/lib/dcr-utils.js.map +1 -0
  15. package/dist/cjs/lib/dcr-verify.d.cts +53 -0
  16. package/dist/cjs/lib/dcr-verify.d.ts +53 -0
  17. package/dist/cjs/lib/dcr-verify.js +193 -0
  18. package/dist/cjs/lib/dcr-verify.js.map +1 -0
  19. package/dist/cjs/lib/fetch-with-timeout.d.cts +14 -0
  20. package/dist/cjs/lib/fetch-with-timeout.d.ts +14 -0
  21. package/dist/cjs/lib/fetch-with-timeout.js +257 -0
  22. package/dist/cjs/lib/fetch-with-timeout.js.map +1 -0
  23. package/dist/cjs/lib/token-verifier.d.cts +44 -0
  24. package/dist/cjs/lib/token-verifier.d.ts +44 -0
  25. package/dist/cjs/lib/token-verifier.js +253 -0
  26. package/dist/cjs/lib/token-verifier.js.map +1 -0
  27. package/dist/cjs/package.json +1 -0
  28. package/dist/cjs/providers/dcr.d.cts +110 -0
  29. package/dist/cjs/providers/dcr.d.ts +110 -0
  30. package/dist/cjs/providers/dcr.js +600 -0
  31. package/dist/cjs/providers/dcr.js.map +1 -0
  32. package/dist/cjs/providers/device-code.d.cts +179 -0
  33. package/dist/cjs/providers/device-code.d.ts +179 -0
  34. package/dist/cjs/providers/device-code.js +896 -0
  35. package/dist/cjs/providers/device-code.js.map +1 -0
  36. package/dist/cjs/providers/loopback-oauth.d.cts +125 -0
  37. package/dist/cjs/providers/loopback-oauth.d.ts +125 -0
  38. package/dist/cjs/providers/loopback-oauth.js +1325 -0
  39. package/dist/cjs/providers/loopback-oauth.js.map +1 -0
  40. package/dist/cjs/schemas/index.d.cts +20 -0
  41. package/dist/cjs/schemas/index.d.ts +20 -0
  42. package/dist/cjs/schemas/index.js +37 -0
  43. package/dist/cjs/schemas/index.js.map +1 -0
  44. package/dist/cjs/setup/config.d.cts +113 -0
  45. package/dist/cjs/setup/config.d.ts +113 -0
  46. package/dist/cjs/setup/config.js +246 -0
  47. package/dist/cjs/setup/config.js.map +1 -0
  48. package/dist/cjs/types.d.cts +188 -0
  49. package/dist/cjs/types.d.ts +188 -0
  50. package/dist/cjs/types.js +18 -0
  51. package/dist/cjs/types.js.map +1 -0
  52. package/dist/esm/index.d.ts +16 -0
  53. package/dist/esm/index.js +16 -0
  54. package/dist/esm/index.js.map +1 -0
  55. package/dist/esm/lib/dcr-router.d.ts +44 -0
  56. package/dist/esm/lib/dcr-router.js +556 -0
  57. package/dist/esm/lib/dcr-router.js.map +1 -0
  58. package/dist/esm/lib/dcr-utils.d.ts +160 -0
  59. package/dist/esm/lib/dcr-utils.js +270 -0
  60. package/dist/esm/lib/dcr-utils.js.map +1 -0
  61. package/dist/esm/lib/dcr-verify.d.ts +53 -0
  62. package/dist/esm/lib/dcr-verify.js +53 -0
  63. package/dist/esm/lib/dcr-verify.js.map +1 -0
  64. package/dist/esm/lib/fetch-with-timeout.d.ts +14 -0
  65. package/dist/esm/lib/fetch-with-timeout.js +30 -0
  66. package/dist/esm/lib/fetch-with-timeout.js.map +1 -0
  67. package/dist/esm/lib/token-verifier.d.ts +44 -0
  68. package/dist/esm/lib/token-verifier.js +53 -0
  69. package/dist/esm/lib/token-verifier.js.map +1 -0
  70. package/dist/esm/package.json +1 -0
  71. package/dist/esm/providers/dcr.d.ts +110 -0
  72. package/dist/esm/providers/dcr.js +235 -0
  73. package/dist/esm/providers/dcr.js.map +1 -0
  74. package/dist/esm/providers/device-code.d.ts +179 -0
  75. package/dist/esm/providers/device-code.js +417 -0
  76. package/dist/esm/providers/device-code.js.map +1 -0
  77. package/dist/esm/providers/loopback-oauth.d.ts +125 -0
  78. package/dist/esm/providers/loopback-oauth.js +643 -0
  79. package/dist/esm/providers/loopback-oauth.js.map +1 -0
  80. package/dist/esm/schemas/index.d.ts +20 -0
  81. package/dist/esm/schemas/index.js +18 -0
  82. package/dist/esm/schemas/index.js.map +1 -0
  83. package/dist/esm/setup/config.d.ts +113 -0
  84. package/dist/esm/setup/config.js +268 -0
  85. package/dist/esm/setup/config.js.map +1 -0
  86. package/dist/esm/types.d.ts +188 -0
  87. package/dist/esm/types.js +8 -0
  88. package/dist/esm/types.js.map +1 -0
  89. package/package.json +87 -0
@@ -0,0 +1,896 @@
1
+ /**
2
+ * Device Code OAuth Implementation for Microsoft
3
+ *
4
+ * Implements OAuth 2.0 Device Authorization Grant (RFC 8628) for headless/limited-input devices.
5
+ * Designed for scenarios where interactive browser flows are impractical (SSH sessions, CI/CD, etc.).
6
+ *
7
+ * Flow:
8
+ * 1. Request device code from Microsoft endpoint
9
+ * 2. Display user_code and verification_uri to user
10
+ * 3. Poll token endpoint until user completes authentication
11
+ * 4. Cache access token + refresh token to storage
12
+ * 5. Refresh tokens when expired
13
+ *
14
+ * Similar to service accounts in usage pattern: single static identity, minimal account management.
15
+ */ "use strict";
16
+ Object.defineProperty(exports, "__esModule", {
17
+ value: true
18
+ });
19
+ Object.defineProperty(exports, "DeviceCodeProvider", {
20
+ enumerable: true,
21
+ get: function() {
22
+ return DeviceCodeProvider;
23
+ }
24
+ });
25
+ var _oauth = require("@mcp-z/oauth");
26
+ var _open = /*#__PURE__*/ _interop_require_default(require("open"));
27
+ var _fetchwithtimeoutts = require("../lib/fetch-with-timeout.js");
28
+ function _array_like_to_array(arr, len) {
29
+ if (len == null || len > arr.length) len = arr.length;
30
+ for(var i = 0, arr2 = new Array(len); i < len; i++)arr2[i] = arr[i];
31
+ return arr2;
32
+ }
33
+ function _array_without_holes(arr) {
34
+ if (Array.isArray(arr)) return _array_like_to_array(arr);
35
+ }
36
+ function asyncGeneratorStep(gen, resolve, reject, _next, _throw, key, arg) {
37
+ try {
38
+ var info = gen[key](arg);
39
+ var value = info.value;
40
+ } catch (error) {
41
+ reject(error);
42
+ return;
43
+ }
44
+ if (info.done) {
45
+ resolve(value);
46
+ } else {
47
+ Promise.resolve(value).then(_next, _throw);
48
+ }
49
+ }
50
+ function _async_to_generator(fn) {
51
+ return function() {
52
+ var self = this, args = arguments;
53
+ return new Promise(function(resolve, reject) {
54
+ var gen = fn.apply(self, args);
55
+ function _next(value) {
56
+ asyncGeneratorStep(gen, resolve, reject, _next, _throw, "next", value);
57
+ }
58
+ function _throw(err) {
59
+ asyncGeneratorStep(gen, resolve, reject, _next, _throw, "throw", err);
60
+ }
61
+ _next(undefined);
62
+ });
63
+ };
64
+ }
65
+ function _class_call_check(instance, Constructor) {
66
+ if (!(instance instanceof Constructor)) {
67
+ throw new TypeError("Cannot call a class as a function");
68
+ }
69
+ }
70
+ function _define_property(obj, key, value) {
71
+ if (key in obj) {
72
+ Object.defineProperty(obj, key, {
73
+ value: value,
74
+ enumerable: true,
75
+ configurable: true,
76
+ writable: true
77
+ });
78
+ } else {
79
+ obj[key] = value;
80
+ }
81
+ return obj;
82
+ }
83
+ function _instanceof(left, right) {
84
+ if (right != null && typeof Symbol !== "undefined" && right[Symbol.hasInstance]) {
85
+ return !!right[Symbol.hasInstance](left);
86
+ } else {
87
+ return left instanceof right;
88
+ }
89
+ }
90
+ function _interop_require_default(obj) {
91
+ return obj && obj.__esModule ? obj : {
92
+ default: obj
93
+ };
94
+ }
95
+ function _iterable_to_array(iter) {
96
+ if (typeof Symbol !== "undefined" && iter[Symbol.iterator] != null || iter["@@iterator"] != null) return Array.from(iter);
97
+ }
98
+ function _non_iterable_spread() {
99
+ throw new TypeError("Invalid attempt to spread non-iterable instance.\\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.");
100
+ }
101
+ function _object_spread(target) {
102
+ for(var i = 1; i < arguments.length; i++){
103
+ var source = arguments[i] != null ? arguments[i] : {};
104
+ var ownKeys = Object.keys(source);
105
+ if (typeof Object.getOwnPropertySymbols === "function") {
106
+ ownKeys = ownKeys.concat(Object.getOwnPropertySymbols(source).filter(function(sym) {
107
+ return Object.getOwnPropertyDescriptor(source, sym).enumerable;
108
+ }));
109
+ }
110
+ ownKeys.forEach(function(key) {
111
+ _define_property(target, key, source[key]);
112
+ });
113
+ }
114
+ return target;
115
+ }
116
+ function ownKeys(object, enumerableOnly) {
117
+ var keys = Object.keys(object);
118
+ if (Object.getOwnPropertySymbols) {
119
+ var symbols = Object.getOwnPropertySymbols(object);
120
+ if (enumerableOnly) {
121
+ symbols = symbols.filter(function(sym) {
122
+ return Object.getOwnPropertyDescriptor(object, sym).enumerable;
123
+ });
124
+ }
125
+ keys.push.apply(keys, symbols);
126
+ }
127
+ return keys;
128
+ }
129
+ function _object_spread_props(target, source) {
130
+ source = source != null ? source : {};
131
+ if (Object.getOwnPropertyDescriptors) {
132
+ Object.defineProperties(target, Object.getOwnPropertyDescriptors(source));
133
+ } else {
134
+ ownKeys(Object(source)).forEach(function(key) {
135
+ Object.defineProperty(target, key, Object.getOwnPropertyDescriptor(source, key));
136
+ });
137
+ }
138
+ return target;
139
+ }
140
+ function _to_consumable_array(arr) {
141
+ return _array_without_holes(arr) || _iterable_to_array(arr) || _unsupported_iterable_to_array(arr) || _non_iterable_spread();
142
+ }
143
+ function _unsupported_iterable_to_array(o, minLen) {
144
+ if (!o) return;
145
+ if (typeof o === "string") return _array_like_to_array(o, minLen);
146
+ var n = Object.prototype.toString.call(o).slice(8, -1);
147
+ if (n === "Object" && o.constructor) n = o.constructor.name;
148
+ if (n === "Map" || n === "Set") return Array.from(n);
149
+ if (n === "Arguments" || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(n)) return _array_like_to_array(o, minLen);
150
+ }
151
+ function _ts_generator(thisArg, body) {
152
+ var f, y, t, _ = {
153
+ label: 0,
154
+ sent: function() {
155
+ if (t[0] & 1) throw t[1];
156
+ return t[1];
157
+ },
158
+ trys: [],
159
+ ops: []
160
+ }, g = Object.create((typeof Iterator === "function" ? Iterator : Object).prototype), d = Object.defineProperty;
161
+ return d(g, "next", {
162
+ value: verb(0)
163
+ }), d(g, "throw", {
164
+ value: verb(1)
165
+ }), d(g, "return", {
166
+ value: verb(2)
167
+ }), typeof Symbol === "function" && d(g, Symbol.iterator, {
168
+ value: function() {
169
+ return this;
170
+ }
171
+ }), g;
172
+ function verb(n) {
173
+ return function(v) {
174
+ return step([
175
+ n,
176
+ v
177
+ ]);
178
+ };
179
+ }
180
+ function step(op) {
181
+ if (f) throw new TypeError("Generator is already executing.");
182
+ while(g && (g = 0, op[0] && (_ = 0)), _)try {
183
+ if (f = 1, y && (t = op[0] & 2 ? y["return"] : op[0] ? y["throw"] || ((t = y["return"]) && t.call(y), 0) : y.next) && !(t = t.call(y, op[1])).done) return t;
184
+ if (y = 0, t) op = [
185
+ op[0] & 2,
186
+ t.value
187
+ ];
188
+ switch(op[0]){
189
+ case 0:
190
+ case 1:
191
+ t = op;
192
+ break;
193
+ case 4:
194
+ _.label++;
195
+ return {
196
+ value: op[1],
197
+ done: false
198
+ };
199
+ case 5:
200
+ _.label++;
201
+ y = op[1];
202
+ op = [
203
+ 0
204
+ ];
205
+ continue;
206
+ case 7:
207
+ op = _.ops.pop();
208
+ _.trys.pop();
209
+ continue;
210
+ default:
211
+ if (!(t = _.trys, t = t.length > 0 && t[t.length - 1]) && (op[0] === 6 || op[0] === 2)) {
212
+ _ = 0;
213
+ continue;
214
+ }
215
+ if (op[0] === 3 && (!t || op[1] > t[0] && op[1] < t[3])) {
216
+ _.label = op[1];
217
+ break;
218
+ }
219
+ if (op[0] === 6 && _.label < t[1]) {
220
+ _.label = t[1];
221
+ t = op;
222
+ break;
223
+ }
224
+ if (t && _.label < t[2]) {
225
+ _.label = t[2];
226
+ _.ops.push(op);
227
+ break;
228
+ }
229
+ if (t[2]) _.ops.pop();
230
+ _.trys.pop();
231
+ continue;
232
+ }
233
+ op = body.call(thisArg, _);
234
+ } catch (e) {
235
+ op = [
236
+ 6,
237
+ e
238
+ ];
239
+ y = 0;
240
+ } finally{
241
+ f = t = 0;
242
+ }
243
+ if (op[0] & 5) throw op[1];
244
+ return {
245
+ value: op[0] ? op[1] : void 0,
246
+ done: true
247
+ };
248
+ }
249
+ }
250
+ var DeviceCodeProvider = /*#__PURE__*/ function() {
251
+ "use strict";
252
+ function DeviceCodeProvider(config) {
253
+ _class_call_check(this, DeviceCodeProvider);
254
+ this.config = config;
255
+ }
256
+ var _proto = DeviceCodeProvider.prototype;
257
+ /**
258
+ * Start device code flow and poll for token
259
+ *
260
+ * 1. POST to /devicecode endpoint to get device_code and user_code
261
+ * 2. Display verification instructions to user
262
+ * 3. Poll /token endpoint every interval seconds
263
+ * 4. Handle authorization_pending, slow_down, expired_token errors
264
+ * 5. Return token when user completes authentication
265
+ */ _proto.startDeviceCodeFlow = function startDeviceCodeFlow(accountId) {
266
+ return _async_to_generator(function() {
267
+ var _this_config, clientId, tenantId, scope, logger, headless, deviceCodeEndpoint, deviceCodeResponse, errorText, deviceCodeData, device_code, user_code, verification_uri, verification_uri_complete, expires_in, interval, urlToOpen, error;
268
+ return _ts_generator(this, function(_state) {
269
+ switch(_state.label){
270
+ case 0:
271
+ _this_config = this.config, clientId = _this_config.clientId, tenantId = _this_config.tenantId, scope = _this_config.scope, logger = _this_config.logger, headless = _this_config.headless;
272
+ // Step 1: Request device code
273
+ deviceCodeEndpoint = "https://login.microsoftonline.com/".concat(tenantId, "/oauth2/v2.0/devicecode");
274
+ logger.debug('Requesting device code', {
275
+ endpoint: deviceCodeEndpoint
276
+ });
277
+ return [
278
+ 4,
279
+ (0, _fetchwithtimeoutts.fetchWithTimeout)(deviceCodeEndpoint, {
280
+ method: 'POST',
281
+ headers: {
282
+ 'Content-Type': 'application/x-www-form-urlencoded'
283
+ },
284
+ body: new URLSearchParams({
285
+ client_id: clientId,
286
+ scope: scope
287
+ })
288
+ })
289
+ ];
290
+ case 1:
291
+ deviceCodeResponse = _state.sent();
292
+ if (!!deviceCodeResponse.ok) return [
293
+ 3,
294
+ 3
295
+ ];
296
+ return [
297
+ 4,
298
+ deviceCodeResponse.text()
299
+ ];
300
+ case 2:
301
+ errorText = _state.sent();
302
+ throw new Error("Device code request failed (HTTP ".concat(deviceCodeResponse.status, "): ").concat(errorText));
303
+ case 3:
304
+ return [
305
+ 4,
306
+ deviceCodeResponse.json()
307
+ ];
308
+ case 4:
309
+ deviceCodeData = _state.sent();
310
+ device_code = deviceCodeData.device_code, user_code = deviceCodeData.user_code, verification_uri = deviceCodeData.verification_uri, verification_uri_complete = deviceCodeData.verification_uri_complete, expires_in = deviceCodeData.expires_in, interval = deviceCodeData.interval;
311
+ // Step 2: Display instructions to user
312
+ logger.info('━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━');
313
+ logger.info('Device code authentication required');
314
+ logger.info('');
315
+ logger.info("Please visit: ".concat(verification_uri_complete || verification_uri));
316
+ logger.info("And enter code: ".concat(user_code));
317
+ logger.info('');
318
+ logger.info("Code expires in ".concat(expires_in, " seconds"));
319
+ logger.info('Waiting for authentication...');
320
+ logger.info('━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━');
321
+ if (!!headless) return [
322
+ 3,
323
+ 8
324
+ ];
325
+ urlToOpen = verification_uri_complete || verification_uri;
326
+ _state.label = 5;
327
+ case 5:
328
+ _state.trys.push([
329
+ 5,
330
+ 7,
331
+ ,
332
+ 8
333
+ ]);
334
+ return [
335
+ 4,
336
+ (0, _open.default)(urlToOpen)
337
+ ];
338
+ case 6:
339
+ _state.sent();
340
+ logger.debug('Opened browser to verification URL', {
341
+ url: urlToOpen
342
+ });
343
+ return [
344
+ 3,
345
+ 8
346
+ ];
347
+ case 7:
348
+ error = _state.sent();
349
+ logger.debug('Failed to open browser', {
350
+ error: _instanceof(error, Error) ? error.message : String(error)
351
+ });
352
+ return [
353
+ 3,
354
+ 8
355
+ ];
356
+ case 8:
357
+ return [
358
+ 4,
359
+ this.pollForToken(device_code, interval || 5, accountId)
360
+ ];
361
+ case 9:
362
+ // Step 3: Poll token endpoint
363
+ return [
364
+ 2,
365
+ _state.sent()
366
+ ];
367
+ }
368
+ });
369
+ }).call(this);
370
+ };
371
+ /**
372
+ * Poll Microsoft token endpoint until user completes authentication
373
+ *
374
+ * Handles Microsoft-specific error codes:
375
+ * - authorization_pending: User hasn't completed auth yet, keep polling
376
+ * - slow_down: Increase polling interval by 5 seconds
377
+ * - authorization_declined: User denied authorization
378
+ * - expired_token: Device code expired (typically after 15 minutes)
379
+ */ _proto.pollForToken = function pollForToken(deviceCode, intervalSeconds, accountId) {
380
+ return _async_to_generator(function() {
381
+ var _this_config, clientId, tenantId, logger, service, tokenStore, tokenEndpoint, currentInterval, startTime, response, responseData, tokenData, token, error, errorDescription;
382
+ return _ts_generator(this, function(_state) {
383
+ switch(_state.label){
384
+ case 0:
385
+ _this_config = this.config, clientId = _this_config.clientId, tenantId = _this_config.tenantId, logger = _this_config.logger, service = _this_config.service, tokenStore = _this_config.tokenStore;
386
+ tokenEndpoint = "https://login.microsoftonline.com/".concat(tenantId, "/oauth2/v2.0/token");
387
+ currentInterval = intervalSeconds;
388
+ startTime = Date.now();
389
+ _state.label = 1;
390
+ case 1:
391
+ if (!true) return [
392
+ 3,
393
+ 7
394
+ ];
395
+ // Wait for polling interval
396
+ return [
397
+ 4,
398
+ new Promise(function(resolve) {
399
+ return setTimeout(resolve, currentInterval * 1000);
400
+ })
401
+ ];
402
+ case 2:
403
+ _state.sent();
404
+ logger.debug('Polling for token', {
405
+ elapsed: Math.floor((Date.now() - startTime) / 1000),
406
+ interval: currentInterval
407
+ });
408
+ return [
409
+ 4,
410
+ (0, _fetchwithtimeoutts.fetchWithTimeout)(tokenEndpoint, {
411
+ method: 'POST',
412
+ headers: {
413
+ 'Content-Type': 'application/x-www-form-urlencoded'
414
+ },
415
+ body: new URLSearchParams({
416
+ grant_type: 'urn:ietf:params:oauth:grant-type:device_code',
417
+ client_id: clientId,
418
+ device_code: deviceCode
419
+ })
420
+ })
421
+ ];
422
+ case 3:
423
+ response = _state.sent();
424
+ return [
425
+ 4,
426
+ response.json()
427
+ ];
428
+ case 4:
429
+ responseData = _state.sent();
430
+ if (!response.ok) return [
431
+ 3,
432
+ 6
433
+ ];
434
+ // Success! Convert to CachedToken and store
435
+ tokenData = responseData;
436
+ token = _object_spread(_object_spread_props(_object_spread({
437
+ accessToken: tokenData.access_token
438
+ }, tokenData.refresh_token && {
439
+ refreshToken: tokenData.refresh_token
440
+ }), {
441
+ expiresAt: Date.now() + (tokenData.expires_in - 60) * 1000
442
+ }), tokenData.scope && {
443
+ scope: tokenData.scope
444
+ });
445
+ // Cache token to storage
446
+ return [
447
+ 4,
448
+ (0, _oauth.setToken)(tokenStore, {
449
+ accountId: accountId,
450
+ service: service
451
+ }, token)
452
+ ];
453
+ case 5:
454
+ _state.sent();
455
+ logger.info('Device code authentication successful', {
456
+ accountId: accountId
457
+ });
458
+ return [
459
+ 2,
460
+ token
461
+ ];
462
+ case 6:
463
+ // Handle error responses
464
+ error = responseData.error;
465
+ errorDescription = responseData.error_description || '';
466
+ if (error === 'authorization_pending') {
467
+ // User hasn't completed auth yet - continue polling
468
+ logger.debug('Authorization pending, waiting for user...');
469
+ return [
470
+ 3,
471
+ 1
472
+ ];
473
+ }
474
+ if (error === 'slow_down') {
475
+ // Microsoft wants us to slow down polling
476
+ currentInterval += 5;
477
+ logger.debug('Received slow_down, increasing interval', {
478
+ newInterval: currentInterval
479
+ });
480
+ return [
481
+ 3,
482
+ 1
483
+ ];
484
+ }
485
+ if (error === 'authorization_declined') {
486
+ throw new Error('User declined authorization. Please restart the authentication flow.');
487
+ }
488
+ if (error === 'expired_token') {
489
+ throw new Error('Device code expired. Please restart the authentication flow.');
490
+ }
491
+ // Unknown error
492
+ throw new Error("Device code flow failed: ".concat(error, " - ").concat(errorDescription));
493
+ case 7:
494
+ return [
495
+ 2
496
+ ];
497
+ }
498
+ });
499
+ }).call(this);
500
+ };
501
+ /**
502
+ * Refresh expired access token using refresh token
503
+ *
504
+ * @param refreshToken - Refresh token from previous authentication
505
+ * @returns New cached token with fresh access token
506
+ */ _proto.refreshAccessToken = function refreshAccessToken(refreshToken) {
507
+ return _async_to_generator(function() {
508
+ var _this_config, clientId, tenantId, scope, logger, tokenEndpoint, response, errorText, tokenData;
509
+ return _ts_generator(this, function(_state) {
510
+ switch(_state.label){
511
+ case 0:
512
+ _this_config = this.config, clientId = _this_config.clientId, tenantId = _this_config.tenantId, scope = _this_config.scope, logger = _this_config.logger;
513
+ tokenEndpoint = "https://login.microsoftonline.com/".concat(tenantId, "/oauth2/v2.0/token");
514
+ logger.debug('Refreshing access token');
515
+ return [
516
+ 4,
517
+ (0, _fetchwithtimeoutts.fetchWithTimeout)(tokenEndpoint, {
518
+ method: 'POST',
519
+ headers: {
520
+ 'Content-Type': 'application/x-www-form-urlencoded'
521
+ },
522
+ body: new URLSearchParams({
523
+ grant_type: 'refresh_token',
524
+ client_id: clientId,
525
+ refresh_token: refreshToken,
526
+ scope: scope
527
+ })
528
+ })
529
+ ];
530
+ case 1:
531
+ response = _state.sent();
532
+ if (!!response.ok) return [
533
+ 3,
534
+ 3
535
+ ];
536
+ return [
537
+ 4,
538
+ response.text()
539
+ ];
540
+ case 2:
541
+ errorText = _state.sent();
542
+ throw new Error("Token refresh failed (HTTP ".concat(response.status, "): ").concat(errorText));
543
+ case 3:
544
+ return [
545
+ 4,
546
+ response.json()
547
+ ];
548
+ case 4:
549
+ tokenData = _state.sent();
550
+ return [
551
+ 2,
552
+ {
553
+ accessToken: tokenData.access_token,
554
+ refreshToken: tokenData.refresh_token || refreshToken,
555
+ expiresAt: Date.now() + (tokenData.expires_in - 60) * 1000,
556
+ scope: tokenData.scope || scope
557
+ }
558
+ ];
559
+ }
560
+ });
561
+ }).call(this);
562
+ };
563
+ /**
564
+ * Check if token is still valid (not expired)
565
+ */ _proto.isTokenValid = function isTokenValid(token) {
566
+ return token.expiresAt !== undefined && token.expiresAt > Date.now();
567
+ };
568
+ /**
569
+ * Get access token for Microsoft Graph API
570
+ *
571
+ * Flow:
572
+ * 1. Check token storage
573
+ * 2. If valid token exists, return it
574
+ * 3. If expired but has refresh token, try refresh
575
+ * 4. Otherwise, start new device code flow
576
+ *
577
+ * @param accountId - Account identifier. Defaults to 'device-code' (fixed identifier for device code flow).
578
+ * @returns Access token for API requests
579
+ */ _proto.getAccessToken = function getAccessToken(accountId) {
580
+ return _async_to_generator(function() {
581
+ var _this_config, logger, service, tokenStore, effectiveAccountId, storedToken, refreshedToken, error, token;
582
+ return _ts_generator(this, function(_state) {
583
+ switch(_state.label){
584
+ case 0:
585
+ _this_config = this.config, logger = _this_config.logger, service = _this_config.service, tokenStore = _this_config.tokenStore;
586
+ effectiveAccountId = accountId !== null && accountId !== void 0 ? accountId : 'device-code';
587
+ logger.debug('Getting access token', {
588
+ service: service,
589
+ accountId: effectiveAccountId
590
+ });
591
+ return [
592
+ 4,
593
+ (0, _oauth.getToken)(tokenStore, {
594
+ accountId: effectiveAccountId,
595
+ service: service
596
+ })
597
+ ];
598
+ case 1:
599
+ storedToken = _state.sent();
600
+ if (storedToken && this.isTokenValid(storedToken)) {
601
+ logger.debug('Using stored access token', {
602
+ accountId: effectiveAccountId
603
+ });
604
+ return [
605
+ 2,
606
+ storedToken.accessToken
607
+ ];
608
+ }
609
+ if (!(storedToken === null || storedToken === void 0 ? void 0 : storedToken.refreshToken)) return [
610
+ 3,
611
+ 6
612
+ ];
613
+ _state.label = 2;
614
+ case 2:
615
+ _state.trys.push([
616
+ 2,
617
+ 5,
618
+ ,
619
+ 6
620
+ ]);
621
+ logger.info('Refreshing expired access token', {
622
+ accountId: effectiveAccountId
623
+ });
624
+ return [
625
+ 4,
626
+ this.refreshAccessToken(storedToken.refreshToken)
627
+ ];
628
+ case 3:
629
+ refreshedToken = _state.sent();
630
+ return [
631
+ 4,
632
+ (0, _oauth.setToken)(tokenStore, {
633
+ accountId: effectiveAccountId,
634
+ service: service
635
+ }, refreshedToken)
636
+ ];
637
+ case 4:
638
+ _state.sent();
639
+ return [
640
+ 2,
641
+ refreshedToken.accessToken
642
+ ];
643
+ case 5:
644
+ error = _state.sent();
645
+ logger.info('Token refresh failed', {
646
+ accountId: effectiveAccountId,
647
+ error: _instanceof(error, Error) ? error.message : String(error)
648
+ });
649
+ // In headless mode, cannot start interactive device code flow
650
+ if (this.config.headless) {
651
+ throw new Error("Token refresh failed in headless mode. Cannot start interactive device code flow. Error: ".concat(_instanceof(error, Error) ? error.message : String(error)));
652
+ }
653
+ return [
654
+ 3,
655
+ 6
656
+ ];
657
+ case 6:
658
+ // No valid token - check if we can start device code flow
659
+ if (this.config.headless) {
660
+ throw new Error('No valid token available in headless mode. Device code flow requires user interaction. ' + 'Please run authentication flow interactively first or provide valid tokens.');
661
+ }
662
+ // Interactive mode - start device code flow
663
+ logger.info('Starting device code flow', {
664
+ accountId: effectiveAccountId
665
+ });
666
+ return [
667
+ 4,
668
+ this.startDeviceCodeFlow(effectiveAccountId)
669
+ ];
670
+ case 7:
671
+ token = _state.sent();
672
+ return [
673
+ 2,
674
+ token.accessToken
675
+ ];
676
+ }
677
+ });
678
+ }).call(this);
679
+ };
680
+ /**
681
+ * Get user email from Microsoft Graph /me endpoint (pure query)
682
+ *
683
+ * @param accountId - Account identifier
684
+ * @returns User's email address (userPrincipalName or mail field)
685
+ */ _proto.getUserEmail = function getUserEmail(accountId) {
686
+ return _async_to_generator(function() {
687
+ var logger, token, response, errorText, userData, email;
688
+ return _ts_generator(this, function(_state) {
689
+ switch(_state.label){
690
+ case 0:
691
+ logger = this.config.logger;
692
+ return [
693
+ 4,
694
+ this.getAccessToken(accountId)
695
+ ];
696
+ case 1:
697
+ token = _state.sent();
698
+ logger.debug('Fetching user email from Microsoft Graph');
699
+ return [
700
+ 4,
701
+ (0, _fetchwithtimeoutts.fetchWithTimeout)('https://graph.microsoft.com/v1.0/me', {
702
+ headers: {
703
+ Authorization: "Bearer ".concat(token)
704
+ }
705
+ })
706
+ ];
707
+ case 2:
708
+ response = _state.sent();
709
+ if (!!response.ok) return [
710
+ 3,
711
+ 4
712
+ ];
713
+ return [
714
+ 4,
715
+ response.text()
716
+ ];
717
+ case 3:
718
+ errorText = _state.sent();
719
+ throw new Error("Failed to get user email (HTTP ".concat(response.status, "): ").concat(errorText));
720
+ case 4:
721
+ return [
722
+ 4,
723
+ response.json()
724
+ ];
725
+ case 5:
726
+ userData = _state.sent();
727
+ email = userData.userPrincipalName || userData.mail;
728
+ if (!email) {
729
+ throw new Error('User email not found in Microsoft Graph response');
730
+ }
731
+ return [
732
+ 2,
733
+ email
734
+ ];
735
+ }
736
+ });
737
+ }).call(this);
738
+ };
739
+ /**
740
+ * Create auth provider for Microsoft Graph SDK integration
741
+ *
742
+ * Device code provider ALWAYS uses fixed accountId='device-code'
743
+ * This is by design - device code is a single static identity pattern
744
+ *
745
+ * @param accountId - Account identifier (must be 'device-code' or undefined, otherwise throws error)
746
+ * @returns Auth provider with getAccessToken method
747
+ */ _proto.toAuthProvider = function toAuthProvider(accountId) {
748
+ var _this = this;
749
+ // Device code ONLY works with 'device-code' account ID
750
+ if (accountId !== undefined && accountId !== 'device-code') {
751
+ throw new Error("DeviceCodeProvider only supports accountId='device-code', got '".concat(accountId, "'. Device code uses a single static identity pattern."));
752
+ }
753
+ // ALWAYS use fixed 'device-code' account ID
754
+ var getToken = function() {
755
+ return _this.getAccessToken('device-code');
756
+ };
757
+ return {
758
+ getAccessToken: getToken
759
+ };
760
+ };
761
+ /**
762
+ * Create Microsoft Graph AuthenticationProvider for SDK usage
763
+ *
764
+ * @param accountId - Account identifier
765
+ * @returns AuthenticationProvider that provides access tokens
766
+ */ _proto.createAuthProvider = function createAuthProvider(accountId) {
767
+ var _this = this;
768
+ return {
769
+ getAccessToken: function() {
770
+ return _async_to_generator(function() {
771
+ return _ts_generator(this, function(_state) {
772
+ switch(_state.label){
773
+ case 0:
774
+ return [
775
+ 4,
776
+ this.getAccessToken(accountId)
777
+ ];
778
+ case 1:
779
+ return [
780
+ 2,
781
+ _state.sent()
782
+ ];
783
+ }
784
+ });
785
+ }).call(_this);
786
+ }
787
+ };
788
+ };
789
+ /**
790
+ * Create middleware wrapper for single-user authentication
791
+ *
792
+ * Middleware wraps tool, resource, and prompt handlers and injects authContext into extra parameter.
793
+ * Handlers receive MicrosoftAuthProvider via extra.authContext.auth for API calls.
794
+ *
795
+ * @returns Object with withToolAuth, withResourceAuth, withPromptAuth methods
796
+ *
797
+ * @example
798
+ * ```typescript
799
+ * // Server registration
800
+ * const middleware = provider.authMiddleware();
801
+ * const tools = toolFactories.map(f => f()).map(middleware.withToolAuth);
802
+ * const resources = resourceFactories.map(f => f()).map(middleware.withResourceAuth);
803
+ * const prompts = promptFactories.map(f => f()).map(middleware.withPromptAuth);
804
+ *
805
+ * // Tool handler receives auth
806
+ * async function handler({ id }: In, extra: EnrichedExtra) {
807
+ * // extra.authContext.auth is MicrosoftAuthProvider (from middleware)
808
+ * const graph = Client.initWithMiddleware({ authProvider: extra.authContext.auth });
809
+ * }
810
+ * ```
811
+ */ _proto.authMiddleware = function authMiddleware() {
812
+ var _this = this;
813
+ // Shared wrapper logic - extracts extra parameter from specified position
814
+ // Generic T captures the actual module type; handler is cast from unknown to callable
815
+ var wrapAtPosition = function(module, extraPosition) {
816
+ var _this1 = _this;
817
+ var originalHandler = module.handler;
818
+ var wrappedHandler = function() {
819
+ for(var _len = arguments.length, allArgs = new Array(_len), _key = 0; _key < _len; _key++){
820
+ allArgs[_key] = arguments[_key];
821
+ }
822
+ return _async_to_generator(function() {
823
+ var extra, accountId, auth, error;
824
+ return _ts_generator(this, function(_state) {
825
+ switch(_state.label){
826
+ case 0:
827
+ if (allArgs.length <= extraPosition) {
828
+ // Arg-less tool pattern: single argument is both args and extra
829
+ extra = allArgs[0] || {};
830
+ allArgs[0] = extra;
831
+ allArgs[extraPosition] = extra;
832
+ } else {
833
+ extra = allArgs[extraPosition] || {};
834
+ allArgs[extraPosition] = extra;
835
+ }
836
+ _state.label = 1;
837
+ case 1:
838
+ _state.trys.push([
839
+ 1,
840
+ 3,
841
+ ,
842
+ 4
843
+ ]);
844
+ // Use fixed accountId for storage isolation (like service-account pattern)
845
+ accountId = 'device-code';
846
+ // Create Microsoft Graph authentication provider
847
+ auth = this.createAuthProvider(accountId);
848
+ // Inject authContext and logger into extra parameter
849
+ extra.authContext = {
850
+ auth: auth,
851
+ accountId: accountId
852
+ };
853
+ extra.logger = this.config.logger;
854
+ return [
855
+ 4,
856
+ originalHandler.apply(void 0, _to_consumable_array(allArgs))
857
+ ];
858
+ case 2:
859
+ // Call original handler with all args
860
+ return [
861
+ 2,
862
+ _state.sent()
863
+ ];
864
+ case 3:
865
+ error = _state.sent();
866
+ // Wrap auth errors with helpful context
867
+ throw new Error("Device code authentication failed: ".concat(_instanceof(error, Error) ? error.message : String(error)));
868
+ case 4:
869
+ return [
870
+ 2
871
+ ];
872
+ }
873
+ });
874
+ }).call(_this1);
875
+ };
876
+ return _object_spread_props(_object_spread({}, module), {
877
+ handler: wrappedHandler
878
+ });
879
+ };
880
+ return {
881
+ // Use structural constraints to avoid contravariance check on handler type.
882
+ // wrapAtPosition is now generic and returns T directly.
883
+ withToolAuth: function(module) {
884
+ return wrapAtPosition(module, 1);
885
+ },
886
+ withResourceAuth: function(module) {
887
+ return wrapAtPosition(module, 2);
888
+ },
889
+ withPromptAuth: function(module) {
890
+ return wrapAtPosition(module, 0);
891
+ }
892
+ };
893
+ };
894
+ return DeviceCodeProvider;
895
+ }();
896
+ /* CJS INTEROP */ if (exports.__esModule && exports.default) { try { Object.defineProperty(exports.default, '__esModule', { value: true }); for (var key in exports) { exports.default[key] = exports[key]; } } catch (_) {}; module.exports = exports.default; }