@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.
- package/README.md +8 -0
- package/dist/cjs/index.d.cts +2 -1
- package/dist/cjs/index.d.ts +2 -1
- package/dist/cjs/index.js +4 -0
- package/dist/cjs/index.js.map +1 -1
- package/dist/cjs/lib/dcr-router.js.map +1 -1
- package/dist/cjs/lib/dcr-utils.js.map +1 -1
- package/dist/cjs/lib/dcr-verify.js.map +1 -1
- package/dist/cjs/lib/fetch-with-timeout.js.map +1 -1
- package/dist/cjs/lib/loopback-router.d.cts +8 -0
- package/dist/cjs/lib/loopback-router.d.ts +8 -0
- package/dist/cjs/lib/loopback-router.js +219 -0
- package/dist/cjs/lib/loopback-router.js.map +1 -0
- package/dist/cjs/lib/token-verifier.js.map +1 -1
- package/dist/cjs/providers/dcr.js.map +1 -1
- package/dist/cjs/providers/loopback-oauth.d.cts +15 -17
- package/dist/cjs/providers/loopback-oauth.d.ts +15 -17
- package/dist/cjs/providers/loopback-oauth.js +223 -156
- package/dist/cjs/providers/loopback-oauth.js.map +1 -1
- package/dist/cjs/providers/service-account.js.map +1 -1
- package/dist/cjs/schemas/index.js.map +1 -1
- package/dist/cjs/setup/config.d.cts +6 -1
- package/dist/cjs/setup/config.d.ts +6 -1
- package/dist/cjs/setup/config.js +3 -0
- package/dist/cjs/setup/config.js.map +1 -1
- package/dist/cjs/types.js.map +1 -1
- package/dist/esm/index.d.ts +2 -1
- package/dist/esm/index.js +1 -0
- package/dist/esm/index.js.map +1 -1
- package/dist/esm/lib/dcr-router.js.map +1 -1
- package/dist/esm/lib/dcr-utils.js.map +1 -1
- package/dist/esm/lib/dcr-verify.js.map +1 -1
- package/dist/esm/lib/fetch-with-timeout.js.map +1 -1
- package/dist/esm/lib/loopback-router.d.ts +8 -0
- package/dist/esm/lib/loopback-router.js +32 -0
- package/dist/esm/lib/loopback-router.js.map +1 -0
- package/dist/esm/lib/token-verifier.js.map +1 -1
- package/dist/esm/providers/dcr.js.map +1 -1
- package/dist/esm/providers/loopback-oauth.d.ts +15 -17
- package/dist/esm/providers/loopback-oauth.js +152 -114
- package/dist/esm/providers/loopback-oauth.js.map +1 -1
- package/dist/esm/providers/service-account.js.map +1 -1
- package/dist/esm/schemas/index.js.map +1 -1
- package/dist/esm/setup/config.d.ts +6 -1
- package/dist/esm/setup/config.js +4 -0
- package/dist/esm/setup/config.js.map +1 -1
- package/dist/esm/types.js.map +1 -1
- 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,
|
|
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 -
|
|
404
|
-
|
|
405
|
-
if (!
|
|
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
|
-
//
|
|
410
|
-
|
|
411
|
-
|
|
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
|
-
|
|
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
|
-
|
|
418
|
-
|
|
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
|
-
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
|
|
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:
|
|
437
|
-
url: authUrl.toString()
|
|
438
|
-
|
|
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
|
-
//
|
|
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,
|
|
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
|
-
//
|
|
779
|
-
|
|
780
|
-
|
|
781
|
-
|
|
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
|
-
|
|
788
|
-
|
|
789
|
-
|
|
790
|
-
|
|
791
|
-
|
|
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
|
-
|
|
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
|
|
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
|
-
|
|
803
|
-
|
|
804
|
-
|
|
805
|
-
|
|
806
|
-
|
|
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 (
|
|
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
|
|
949
|
-
server.listen(
|
|
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
|
|
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 = "
|
|
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.
|