@mcp-z/oauth-google 1.0.0 → 1.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (48) hide show
  1. package/README.md +8 -0
  2. package/dist/cjs/index.d.cts +2 -1
  3. package/dist/cjs/index.d.ts +2 -1
  4. package/dist/cjs/index.js +4 -0
  5. package/dist/cjs/index.js.map +1 -1
  6. package/dist/cjs/lib/dcr-router.js.map +1 -1
  7. package/dist/cjs/lib/dcr-utils.js.map +1 -1
  8. package/dist/cjs/lib/dcr-verify.js.map +1 -1
  9. package/dist/cjs/lib/fetch-with-timeout.js.map +1 -1
  10. package/dist/cjs/lib/loopback-router.d.cts +8 -0
  11. package/dist/cjs/lib/loopback-router.d.ts +8 -0
  12. package/dist/cjs/lib/loopback-router.js +219 -0
  13. package/dist/cjs/lib/loopback-router.js.map +1 -0
  14. package/dist/cjs/lib/token-verifier.js.map +1 -1
  15. package/dist/cjs/providers/dcr.js.map +1 -1
  16. package/dist/cjs/providers/loopback-oauth.d.cts +15 -17
  17. package/dist/cjs/providers/loopback-oauth.d.ts +15 -17
  18. package/dist/cjs/providers/loopback-oauth.js +223 -156
  19. package/dist/cjs/providers/loopback-oauth.js.map +1 -1
  20. package/dist/cjs/providers/service-account.js.map +1 -1
  21. package/dist/cjs/schemas/index.js.map +1 -1
  22. package/dist/cjs/setup/config.d.cts +6 -1
  23. package/dist/cjs/setup/config.d.ts +6 -1
  24. package/dist/cjs/setup/config.js +3 -0
  25. package/dist/cjs/setup/config.js.map +1 -1
  26. package/dist/cjs/types.js.map +1 -1
  27. package/dist/esm/index.d.ts +2 -1
  28. package/dist/esm/index.js +1 -0
  29. package/dist/esm/index.js.map +1 -1
  30. package/dist/esm/lib/dcr-router.js.map +1 -1
  31. package/dist/esm/lib/dcr-utils.js.map +1 -1
  32. package/dist/esm/lib/dcr-verify.js.map +1 -1
  33. package/dist/esm/lib/fetch-with-timeout.js.map +1 -1
  34. package/dist/esm/lib/loopback-router.d.ts +8 -0
  35. package/dist/esm/lib/loopback-router.js +32 -0
  36. package/dist/esm/lib/loopback-router.js.map +1 -0
  37. package/dist/esm/lib/token-verifier.js.map +1 -1
  38. package/dist/esm/providers/dcr.js.map +1 -1
  39. package/dist/esm/providers/loopback-oauth.d.ts +15 -17
  40. package/dist/esm/providers/loopback-oauth.js +152 -114
  41. package/dist/esm/providers/loopback-oauth.js.map +1 -1
  42. package/dist/esm/providers/service-account.js.map +1 -1
  43. package/dist/esm/schemas/index.js.map +1 -1
  44. package/dist/esm/setup/config.d.ts +6 -1
  45. package/dist/esm/setup/config.js +4 -0
  46. package/dist/esm/setup/config.js.map +1 -1
  47. package/dist/esm/types.js.map +1 -1
  48. package/package.json +1 -1
@@ -22,6 +22,7 @@ _export(exports, {
22
22
  }
23
23
  });
24
24
  var _oauth = require("@mcp-z/oauth");
25
+ var _crypto = require("crypto");
25
26
  var _googleauthlibrary = require("google-auth-library");
26
27
  var _http = /*#__PURE__*/ _interop_require_wildcard(require("http"));
27
28
  var _open = /*#__PURE__*/ _interop_require_default(require("open"));
@@ -303,7 +304,7 @@ var LoopbackOAuthProvider = /*#__PURE__*/ function() {
303
304
  * @returns Access token for API requests
304
305
  */ _proto.getAccessToken = function getAccessToken(accountId) {
305
306
  return _async_to_generator(function() {
306
- var _this_config, logger, service, tokenStore, effectiveAccountId, _tmp, storedToken, refreshedToken, error, headless, _this_config1, clientId, scope, existingAccounts, hasOtherAccounts, authUrl, hint, baseDescriptor, descriptor, _ref, token, email;
307
+ var _this_config, logger, service, tokenStore, effectiveAccountId, _tmp, storedToken, refreshedToken, error, _this_config1, clientId, scope, redirectUri, _generatePKCE, codeVerifier, codeChallenge, stateId, authUrl, _ref, token, email;
307
308
  return _ts_generator(this, function(_state) {
308
309
  switch(_state.label){
309
310
  case 0:
@@ -400,52 +401,50 @@ var LoopbackOAuthProvider = /*#__PURE__*/ function() {
400
401
  9
401
402
  ];
402
403
  case 9:
403
- // No valid token or no account - check if we can start OAuth flow
404
- headless = this.config.headless;
405
- if (!headless) return [
404
+ // No valid token or no account - need OAuth authentication
405
+ _this_config1 = this.config, clientId = _this_config1.clientId, scope = _this_config1.scope, redirectUri = _this_config1.redirectUri;
406
+ if (!redirectUri) return [
406
407
  3,
407
408
  11
408
409
  ];
409
- // In headless mode (production), cannot start OAuth flow
410
- // Throw AuthRequiredError with auth_url descriptor for MCP tool response
411
- _this_config1 = this.config, clientId = _this_config1.clientId, scope = _this_config1.scope;
410
+ // Persistent callback mode (cloud deployment with configured redirect_uri)
411
+ _generatePKCE = (0, _oauth.generatePKCE)(), codeVerifier = _generatePKCE.verifier, codeChallenge = _generatePKCE.challenge;
412
+ stateId = (0, _crypto.randomUUID)();
413
+ // Store PKCE verifier for callback (5 minute TTL)
412
414
  return [
413
415
  4,
414
- this.getExistingAccounts()
416
+ tokenStore.set("".concat(service, ":pending:").concat(stateId), {
417
+ codeVerifier: codeVerifier,
418
+ createdAt: Date.now()
419
+ }, 5 * 60 * 1000)
415
420
  ];
416
421
  case 10:
417
- existingAccounts = _state.sent();
418
- hasOtherAccounts = effectiveAccountId ? existingAccounts.length > 0 && !existingAccounts.includes(effectiveAccountId) : existingAccounts.length > 0;
419
- // Build informational OAuth URL for headless mode
420
- // Note: No redirect_uri included - user must use account-add tool which starts proper ephemeral server
422
+ _state.sent();
423
+ // Build auth URL with configured redirect_uri
421
424
  authUrl = new URL('https://accounts.google.com/o/oauth2/v2/auth');
422
425
  authUrl.searchParams.set('client_id', clientId);
426
+ authUrl.searchParams.set('redirect_uri', redirectUri);
423
427
  authUrl.searchParams.set('response_type', 'code');
424
428
  authUrl.searchParams.set('scope', scope);
425
429
  authUrl.searchParams.set('access_type', 'offline');
430
+ authUrl.searchParams.set('code_challenge', codeChallenge);
431
+ authUrl.searchParams.set('code_challenge_method', 'S256');
432
+ authUrl.searchParams.set('state', stateId);
426
433
  authUrl.searchParams.set('prompt', 'consent');
427
- if (hasOtherAccounts) {
428
- hint = "Existing ".concat(service, " accounts found. Use account-list to view, account-switch to change account, or account-add to add new account");
429
- } else if (effectiveAccountId) {
430
- hint = "Use account-add to authenticate ".concat(effectiveAccountId);
431
- } else {
432
- hint = 'Use account-add to authenticate interactively';
433
- }
434
- baseDescriptor = {
434
+ logger.info('OAuth required - persistent callback mode', {
435
+ service: service,
436
+ redirectUri: redirectUri
437
+ });
438
+ throw new _typests.AuthRequiredError({
435
439
  kind: 'auth_url',
436
- provider: 'google',
437
- url: authUrl.toString(),
438
- hint: hint
439
- };
440
- descriptor = effectiveAccountId ? _object_spread_props(_object_spread({}, baseDescriptor), {
441
- accountId: effectiveAccountId
442
- }) : baseDescriptor;
443
- throw new _typests.AuthRequiredError(descriptor);
440
+ provider: service,
441
+ url: authUrl.toString()
442
+ });
444
443
  case 11:
445
- // Interactive mode - start ephemeral OAuth flow
444
+ // Ephemeral callback mode (local development)
446
445
  logger.info('Starting ephemeral OAuth flow', {
447
446
  service: service,
448
- headless: headless
447
+ headless: this.config.headless
449
448
  });
450
449
  return [
451
450
  4,
@@ -453,7 +452,6 @@ var LoopbackOAuthProvider = /*#__PURE__*/ function() {
453
452
  ];
454
453
  case 12:
455
454
  _ref = _state.sent(), token = _ref.token, email = _ref.email;
456
- // Store token with email as accountId
457
455
  return [
458
456
  4,
459
457
  (0, _oauth.setToken)(tokenStore, {
@@ -463,7 +461,6 @@ var LoopbackOAuthProvider = /*#__PURE__*/ function() {
463
461
  ];
464
462
  case 13:
465
463
  _state.sent();
466
- // Register account in account management system
467
464
  return [
468
465
  4,
469
466
  (0, _oauth.addAccount)(tokenStore, {
@@ -473,7 +470,6 @@ var LoopbackOAuthProvider = /*#__PURE__*/ function() {
473
470
  ];
474
471
  case 14:
475
472
  _state.sent();
476
- // Set as active account so subsequent getAccessToken() calls find it
477
473
  return [
478
474
  4,
479
475
  (0, _oauth.setActiveAccount)(tokenStore, {
@@ -483,7 +479,6 @@ var LoopbackOAuthProvider = /*#__PURE__*/ function() {
483
479
  ];
484
480
  case 15:
485
481
  _state.sent();
486
- // Store account metadata (email, added timestamp)
487
482
  return [
488
483
  4,
489
484
  (0, _oauth.setAccountInfo)(tokenStore, {
@@ -555,86 +550,6 @@ var LoopbackOAuthProvider = /*#__PURE__*/ function() {
555
550
  return client;
556
551
  };
557
552
  /**
558
- * Authenticate new account with OAuth flow
559
- * Triggers account selection, stores token, registers account
560
- *
561
- * @returns Email address of newly authenticated account
562
- * @throws Error in headless mode (cannot open browser for OAuth)
563
- */ _proto.authenticateNewAccount = function authenticateNewAccount() {
564
- return _async_to_generator(function() {
565
- var _this_config, logger, headless, service, tokenStore, _ref, token, email;
566
- return _ts_generator(this, function(_state) {
567
- switch(_state.label){
568
- case 0:
569
- _this_config = this.config, logger = _this_config.logger, headless = _this_config.headless, service = _this_config.service, tokenStore = _this_config.tokenStore;
570
- if (headless) {
571
- throw new Error('Cannot authenticate new account in headless mode - interactive OAuth required');
572
- }
573
- logger.info('Starting new account authentication', {
574
- service: service
575
- });
576
- return [
577
- 4,
578
- this.performEphemeralOAuthFlow()
579
- ];
580
- case 1:
581
- _ref = _state.sent(), token = _ref.token, email = _ref.email;
582
- // Store token
583
- return [
584
- 4,
585
- (0, _oauth.setToken)(tokenStore, {
586
- accountId: email,
587
- service: service
588
- }, token)
589
- ];
590
- case 2:
591
- _state.sent();
592
- // Register account
593
- return [
594
- 4,
595
- (0, _oauth.addAccount)(tokenStore, {
596
- service: service,
597
- accountId: email
598
- })
599
- ];
600
- case 3:
601
- _state.sent();
602
- // Set as active account
603
- return [
604
- 4,
605
- (0, _oauth.setActiveAccount)(tokenStore, {
606
- service: service,
607
- accountId: email
608
- })
609
- ];
610
- case 4:
611
- _state.sent();
612
- // Store account metadata
613
- return [
614
- 4,
615
- (0, _oauth.setAccountInfo)(tokenStore, {
616
- service: service,
617
- accountId: email
618
- }, {
619
- email: email,
620
- addedAt: new Date().toISOString()
621
- })
622
- ];
623
- case 5:
624
- _state.sent();
625
- logger.info('New account authenticated', {
626
- service: service,
627
- email: email
628
- });
629
- return [
630
- 2,
631
- email
632
- ];
633
- }
634
- });
635
- }).call(this);
636
- };
637
- /**
638
553
  * Get user email from Google's userinfo endpoint (pure query)
639
554
  * Used to query email for existing authenticated account
640
555
  *
@@ -694,24 +609,6 @@ var LoopbackOAuthProvider = /*#__PURE__*/ function() {
694
609
  });
695
610
  }).call(this);
696
611
  };
697
- /**
698
- * Check for existing accounts in token storage (incremental OAuth detection)
699
- *
700
- * Uses key-utils helper for forward compatibility with key format changes.
701
- *
702
- * @returns Array of account IDs that have tokens for this service
703
- */ _proto.getExistingAccounts = function getExistingAccounts() {
704
- return _async_to_generator(function() {
705
- var _this_config, service, tokenStore;
706
- return _ts_generator(this, function(_state) {
707
- _this_config = this.config, service = _this_config.service, tokenStore = _this_config.tokenStore;
708
- return [
709
- 2,
710
- (0, _oauth.listAccountIds)(tokenStore, service)
711
- ];
712
- });
713
- }).call(this);
714
- };
715
612
  _proto.isTokenValid = function isTokenValid(token) {
716
613
  if (!token.expiresAt) return true; // No expiry = assume valid
717
614
  return Date.now() < token.expiresAt - 60000; // 1 minute buffer
@@ -771,46 +668,50 @@ var LoopbackOAuthProvider = /*#__PURE__*/ function() {
771
668
  };
772
669
  _proto.performEphemeralOAuthFlow = function performEphemeralOAuthFlow() {
773
670
  return _async_to_generator(function() {
774
- var _this, _this_config, clientId, scope, headless, logger, configRedirectUri, targetHost, targetPort, targetProtocol, callbackPath, useConfiguredUri, parsed;
671
+ var _this, _this_config, clientId, scope, headless, logger, configRedirectUri, listenHost, listenPort, callbackPath, useConfiguredUri, parsed, isLoopback, envPort;
775
672
  return _ts_generator(this, function(_state) {
776
673
  _this = this;
777
674
  _this_config = this.config, clientId = _this_config.clientId, scope = _this_config.scope, headless = _this_config.headless, logger = _this_config.logger, configRedirectUri = _this_config.redirectUri;
778
- // Parse redirectUri if provided to extract host, protocol, port, and path
779
- targetHost = 'localhost'; // Default: localhost (match registered redirect URI)
780
- targetPort = 0; // Default: OS-assigned ephemeral port
781
- targetProtocol = 'http:'; // Default: http
675
+ // Server listen configuration (where ephemeral server binds)
676
+ listenHost = 'localhost'; // Default: localhost for ephemeral loopback
677
+ listenPort = 0; // Default: OS-assigned ephemeral port
678
+ // Redirect URI configuration (what goes in auth URL and token exchange)
782
679
  callbackPath = '/callback'; // Default callback path
783
680
  useConfiguredUri = false;
784
681
  if (configRedirectUri) {
785
682
  try {
786
683
  parsed = new URL(configRedirectUri);
787
- // Use configured redirect URI as-is for production deployments
788
- targetHost = parsed.hostname;
789
- targetProtocol = parsed.protocol;
790
- // Extract port from URL (use default ports if not specified)
791
- if (parsed.port) {
792
- targetPort = Number.parseInt(parsed.port, 10);
684
+ isLoopback = parsed.hostname === 'localhost' || parsed.hostname === '127.0.0.1';
685
+ if (isLoopback) {
686
+ // Local development: Listen on specific loopback address/port
687
+ listenHost = parsed.hostname;
688
+ listenPort = parsed.port ? Number.parseInt(parsed.port, 10) : 0;
793
689
  } else {
794
- targetPort = parsed.protocol === 'https:' ? 443 : 80;
690
+ // Cloud deployment: Listen on 0.0.0.0 with PORT from environment
691
+ // The redirectUri is the PUBLIC URL (e.g., https://example.com/oauth/callback)
692
+ // The server listens on 0.0.0.0:PORT and the load balancer routes to it
693
+ listenHost = '0.0.0.0';
694
+ envPort = process.env.PORT ? Number.parseInt(process.env.PORT, 10) : undefined;
695
+ listenPort = envPort && Number.isFinite(envPort) ? envPort : 8080;
795
696
  }
796
- // Extract path (default to /callback if URL has no path or just '/')
697
+ // Extract callback path from URL
797
698
  if (parsed.pathname && parsed.pathname !== '/') {
798
699
  callbackPath = parsed.pathname;
799
700
  }
800
701
  useConfiguredUri = true;
801
702
  logger.debug('Using configured redirect URI', {
802
- host: targetHost,
803
- protocol: targetProtocol,
804
- port: targetPort,
805
- path: callbackPath,
806
- redirectUri: configRedirectUri
703
+ listenHost: listenHost,
704
+ listenPort: listenPort,
705
+ callbackPath: callbackPath,
706
+ redirectUri: configRedirectUri,
707
+ isLoopback: isLoopback
807
708
  });
808
709
  } catch (error) {
809
710
  logger.warn('Failed to parse redirectUri, using ephemeral defaults', {
810
711
  redirectUri: configRedirectUri,
811
712
  error: _instanceof(error, Error) ? error.message : String(error)
812
713
  });
813
- // Continue with defaults (127.0.0.1, port 0, http, /callback)
714
+ // Continue with defaults (localhost, port 0, http, /callback)
814
715
  }
815
716
  }
816
717
  return [
@@ -945,8 +846,8 @@ var LoopbackOAuthProvider = /*#__PURE__*/ function() {
945
846
  });
946
847
  }).call(_this);
947
848
  });
948
- // Listen on targetPort (0 for OS assignment, or custom port from redirectUri)
949
- server.listen(targetPort, targetHost, function() {
849
+ // Listen on configured host/port
850
+ server.listen(listenPort, listenHost, function() {
950
851
  var address = server === null || server === void 0 ? void 0 : server.address();
951
852
  if (!address || typeof address === 'string') {
952
853
  server === null || server === void 0 ? void 0 : server.close();
@@ -956,11 +857,11 @@ var LoopbackOAuthProvider = /*#__PURE__*/ function() {
956
857
  serverPort = address.port;
957
858
  // Construct final redirect URI
958
859
  if (useConfiguredUri && configRedirectUri) {
959
- // Use configured redirect URI as-is for production
860
+ // Use configured redirect URI as-is (public URL for cloud, or specific local URL)
960
861
  finalRedirectUri = configRedirectUri;
961
862
  } else {
962
- // Construct ephemeral redirect URI with actual server port
963
- finalRedirectUri = "".concat(targetProtocol, "//").concat(targetHost, ":").concat(serverPort).concat(callbackPath);
863
+ // Construct ephemeral redirect URI with actual server port (default local behavior)
864
+ finalRedirectUri = "http://localhost:".concat(serverPort).concat(callbackPath);
964
865
  }
965
866
  // Build auth URL
966
867
  var authUrl = new URL('https://accounts.google.com/o/oauth2/v2/auth');
@@ -1125,6 +1026,172 @@ var LoopbackOAuthProvider = /*#__PURE__*/ function() {
1125
1026
  }).call(this);
1126
1027
  };
1127
1028
  /**
1029
+ * Handle OAuth callback from persistent endpoint.
1030
+ * Used by HTTP servers with configured redirectUri.
1031
+ *
1032
+ * @param params - OAuth callback parameters
1033
+ * @returns Email and cached token
1034
+ */ _proto.handleOAuthCallback = function handleOAuthCallback(params) {
1035
+ return _async_to_generator(function() {
1036
+ var code, state, _this_config, logger, service, tokenStore, clientId, clientSecret, redirectUri, pendingKey, pendingAuth, body, response, errorText, tokenResponse, email, cachedToken;
1037
+ return _ts_generator(this, function(_state) {
1038
+ switch(_state.label){
1039
+ case 0:
1040
+ code = params.code, state = params.state;
1041
+ _this_config = this.config, logger = _this_config.logger, service = _this_config.service, tokenStore = _this_config.tokenStore, clientId = _this_config.clientId, clientSecret = _this_config.clientSecret, redirectUri = _this_config.redirectUri;
1042
+ if (!state) {
1043
+ throw new Error('Missing state parameter in OAuth callback');
1044
+ }
1045
+ if (!redirectUri) {
1046
+ throw new Error('handleOAuthCallback requires configured redirectUri');
1047
+ }
1048
+ // Load pending auth (includes PKCE verifier)
1049
+ pendingKey = "".concat(service, ":pending:").concat(state);
1050
+ return [
1051
+ 4,
1052
+ tokenStore.get(pendingKey)
1053
+ ];
1054
+ case 1:
1055
+ pendingAuth = _state.sent();
1056
+ if (!pendingAuth) {
1057
+ throw new Error('Invalid or expired OAuth state. Please try again.');
1058
+ }
1059
+ if (!(Date.now() - pendingAuth.createdAt > 5 * 60 * 1000)) return [
1060
+ 3,
1061
+ 3
1062
+ ];
1063
+ return [
1064
+ 4,
1065
+ tokenStore.delete(pendingKey)
1066
+ ];
1067
+ case 2:
1068
+ _state.sent();
1069
+ throw new Error('OAuth state expired. Please try again.');
1070
+ case 3:
1071
+ logger.info('Processing OAuth callback', {
1072
+ service: service,
1073
+ state: state
1074
+ });
1075
+ // Exchange code for token
1076
+ body = new URLSearchParams(_object_spread_props(_object_spread({
1077
+ code: code,
1078
+ client_id: clientId
1079
+ }, clientSecret && {
1080
+ client_secret: clientSecret
1081
+ }), {
1082
+ redirect_uri: redirectUri,
1083
+ grant_type: 'authorization_code',
1084
+ code_verifier: pendingAuth.codeVerifier
1085
+ }));
1086
+ return [
1087
+ 4,
1088
+ fetch('https://oauth2.googleapis.com/token', {
1089
+ method: 'POST',
1090
+ headers: {
1091
+ 'Content-Type': 'application/x-www-form-urlencoded'
1092
+ },
1093
+ body: body.toString()
1094
+ })
1095
+ ];
1096
+ case 4:
1097
+ response = _state.sent();
1098
+ if (!!response.ok) return [
1099
+ 3,
1100
+ 6
1101
+ ];
1102
+ return [
1103
+ 4,
1104
+ response.text()
1105
+ ];
1106
+ case 5:
1107
+ errorText = _state.sent();
1108
+ throw new Error("Token exchange failed: ".concat(response.status, " ").concat(errorText));
1109
+ case 6:
1110
+ return [
1111
+ 4,
1112
+ response.json()
1113
+ ];
1114
+ case 7:
1115
+ tokenResponse = _state.sent();
1116
+ return [
1117
+ 4,
1118
+ this.fetchUserEmailFromToken(tokenResponse.access_token)
1119
+ ];
1120
+ case 8:
1121
+ email = _state.sent();
1122
+ // Create cached token
1123
+ cachedToken = _object_spread({
1124
+ accessToken: tokenResponse.access_token,
1125
+ refreshToken: tokenResponse.refresh_token,
1126
+ expiresAt: tokenResponse.expires_in ? Date.now() + tokenResponse.expires_in * 1000 : undefined
1127
+ }, tokenResponse.scope !== undefined && {
1128
+ scope: tokenResponse.scope
1129
+ });
1130
+ // Store token
1131
+ return [
1132
+ 4,
1133
+ (0, _oauth.setToken)(tokenStore, {
1134
+ accountId: email,
1135
+ service: service
1136
+ }, cachedToken)
1137
+ ];
1138
+ case 9:
1139
+ _state.sent();
1140
+ // Add account and set as active
1141
+ return [
1142
+ 4,
1143
+ (0, _oauth.addAccount)(tokenStore, {
1144
+ service: service,
1145
+ accountId: email
1146
+ })
1147
+ ];
1148
+ case 10:
1149
+ _state.sent();
1150
+ return [
1151
+ 4,
1152
+ (0, _oauth.setActiveAccount)(tokenStore, {
1153
+ service: service,
1154
+ accountId: email
1155
+ })
1156
+ ];
1157
+ case 11:
1158
+ _state.sent();
1159
+ // Store account metadata
1160
+ return [
1161
+ 4,
1162
+ (0, _oauth.setAccountInfo)(tokenStore, {
1163
+ service: service,
1164
+ accountId: email
1165
+ }, {
1166
+ email: email,
1167
+ addedAt: new Date().toISOString()
1168
+ })
1169
+ ];
1170
+ case 12:
1171
+ _state.sent();
1172
+ // Clean up pending auth
1173
+ return [
1174
+ 4,
1175
+ tokenStore.delete(pendingKey)
1176
+ ];
1177
+ case 13:
1178
+ _state.sent();
1179
+ logger.info('OAuth callback completed', {
1180
+ service: service,
1181
+ email: email
1182
+ });
1183
+ return [
1184
+ 2,
1185
+ {
1186
+ email: email,
1187
+ token: cachedToken
1188
+ }
1189
+ ];
1190
+ }
1191
+ });
1192
+ }).call(this);
1193
+ };
1194
+ /**
1128
1195
  * Create authentication middleware for MCP tools, resources, and prompts
1129
1196
  *
1130
1197
  * Returns position-aware middleware wrappers that enrich handlers with authentication context.