@mcp-z/client 1.1.1 → 1.2.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/README.md +5 -1
- package/dist/cjs/auth/capability-discovery.js +13 -7
- package/dist/cjs/auth/capability-discovery.js.map +1 -1
- package/dist/cjs/auth/discovery-fetch.d.cts +35 -0
- package/dist/cjs/auth/discovery-fetch.d.ts +35 -0
- package/dist/cjs/auth/discovery-fetch.js +658 -0
- package/dist/cjs/auth/discovery-fetch.js.map +1 -0
- package/dist/cjs/auth/index.d.cts +1 -0
- package/dist/cjs/auth/index.d.ts +1 -0
- package/dist/cjs/auth/index.js +7 -0
- package/dist/cjs/auth/index.js.map +1 -1
- package/dist/cjs/auth/interactive-oauth-flow.d.cts +12 -12
- package/dist/cjs/auth/interactive-oauth-flow.d.ts +12 -12
- package/dist/cjs/auth/interactive-oauth-flow.js +22 -16
- package/dist/cjs/auth/interactive-oauth-flow.js.map +1 -1
- package/dist/cjs/auth/rfc9728-discovery.d.cts +12 -25
- package/dist/cjs/auth/rfc9728-discovery.d.ts +12 -25
- package/dist/cjs/auth/rfc9728-discovery.js +59 -48
- package/dist/cjs/auth/rfc9728-discovery.js.map +1 -1
- package/dist/cjs/auth/types.d.cts +16 -0
- package/dist/cjs/auth/types.d.ts +16 -0
- package/dist/cjs/auth/types.js.map +1 -1
- package/dist/cjs/dcr/dcr-authenticator.d.cts +3 -4
- package/dist/cjs/dcr/dcr-authenticator.d.ts +3 -4
- package/dist/cjs/dcr/dcr-authenticator.js +22 -12
- package/dist/cjs/dcr/dcr-authenticator.js.map +1 -1
- package/dist/cjs/dcr/dynamic-client-registrar.d.cts +6 -17
- package/dist/cjs/dcr/dynamic-client-registrar.d.ts +6 -17
- package/dist/cjs/dcr/dynamic-client-registrar.js +10 -16
- package/dist/cjs/dcr/dynamic-client-registrar.js.map +1 -1
- package/dist/cjs/index.d.cts +1 -0
- package/dist/cjs/index.d.ts +1 -0
- package/dist/cjs/index.js +7 -0
- package/dist/cjs/index.js.map +1 -1
- package/dist/esm/auth/capability-discovery.js +12 -6
- package/dist/esm/auth/capability-discovery.js.map +1 -1
- package/dist/esm/auth/discovery-fetch.d.ts +35 -0
- package/dist/esm/auth/discovery-fetch.js +184 -0
- package/dist/esm/auth/discovery-fetch.js.map +1 -0
- package/dist/esm/auth/index.d.ts +1 -0
- package/dist/esm/auth/index.js +1 -0
- package/dist/esm/auth/index.js.map +1 -1
- package/dist/esm/auth/interactive-oauth-flow.d.ts +12 -12
- package/dist/esm/auth/interactive-oauth-flow.js +25 -16
- package/dist/esm/auth/interactive-oauth-flow.js.map +1 -1
- package/dist/esm/auth/rfc9728-discovery.d.ts +12 -25
- package/dist/esm/auth/rfc9728-discovery.js +49 -56
- package/dist/esm/auth/rfc9728-discovery.js.map +1 -1
- package/dist/esm/auth/types.d.ts +16 -0
- package/dist/esm/auth/types.js.map +1 -1
- package/dist/esm/dcr/dcr-authenticator.d.ts +3 -4
- package/dist/esm/dcr/dcr-authenticator.js +20 -11
- package/dist/esm/dcr/dcr-authenticator.js.map +1 -1
- package/dist/esm/dcr/dynamic-client-registrar.d.ts +6 -17
- package/dist/esm/dcr/dynamic-client-registrar.js +13 -18
- package/dist/esm/dcr/dynamic-client-registrar.js.map +1 -1
- package/dist/esm/index.d.ts +1 -0
- package/dist/esm/index.js +1 -0
- package/dist/esm/index.js.map +1 -1
- package/package.json +2 -7
|
@@ -3,6 +3,7 @@
|
|
|
3
3
|
* Exports public API for OAuth authentication only (DCR moved to ../dcr/)
|
|
4
4
|
*/
|
|
5
5
|
export { probeAuthCapabilities } from './capability-discovery.js';
|
|
6
|
+
export { DiscoveryFetchError, isLoopbackUrl } from './discovery-fetch.js';
|
|
6
7
|
export { InteractiveOAuthFlow } from './interactive-oauth-flow.js';
|
|
7
8
|
export type { OAuthCallbackListenerOptions } from './oauth-callback-listener.js';
|
|
8
9
|
export { OAuthCallbackListener } from './oauth-callback-listener.js';
|
package/dist/cjs/auth/index.d.ts
CHANGED
|
@@ -3,6 +3,7 @@
|
|
|
3
3
|
* Exports public API for OAuth authentication only (DCR moved to ../dcr/)
|
|
4
4
|
*/
|
|
5
5
|
export { probeAuthCapabilities } from './capability-discovery.js';
|
|
6
|
+
export { DiscoveryFetchError, isLoopbackUrl } from './discovery-fetch.js';
|
|
6
7
|
export { InteractiveOAuthFlow } from './interactive-oauth-flow.js';
|
|
7
8
|
export type { OAuthCallbackListenerOptions } from './oauth-callback-listener.js';
|
|
8
9
|
export { OAuthCallbackListener } from './oauth-callback-listener.js';
|
package/dist/cjs/auth/index.js
CHANGED
|
@@ -12,17 +12,24 @@ function _export(target, all) {
|
|
|
12
12
|
});
|
|
13
13
|
}
|
|
14
14
|
_export(exports, {
|
|
15
|
+
get DiscoveryFetchError () {
|
|
16
|
+
return _discoveryfetchts.DiscoveryFetchError;
|
|
17
|
+
},
|
|
15
18
|
get InteractiveOAuthFlow () {
|
|
16
19
|
return _interactiveoauthflowts.InteractiveOAuthFlow;
|
|
17
20
|
},
|
|
18
21
|
get OAuthCallbackListener () {
|
|
19
22
|
return _oauthcallbacklistenerts.OAuthCallbackListener;
|
|
20
23
|
},
|
|
24
|
+
get isLoopbackUrl () {
|
|
25
|
+
return _discoveryfetchts.isLoopbackUrl;
|
|
26
|
+
},
|
|
21
27
|
get probeAuthCapabilities () {
|
|
22
28
|
return _capabilitydiscoveryts.probeAuthCapabilities;
|
|
23
29
|
}
|
|
24
30
|
});
|
|
25
31
|
var _capabilitydiscoveryts = require("./capability-discovery.js");
|
|
32
|
+
var _discoveryfetchts = require("./discovery-fetch.js");
|
|
26
33
|
var _interactiveoauthflowts = require("./interactive-oauth-flow.js");
|
|
27
34
|
var _oauthcallbacklistenerts = require("./oauth-callback-listener.js");
|
|
28
35
|
/* 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; }
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["/Users/kevin/Dev/OpenSource/ai/mcp-z/client/src/auth/index.ts"],"sourcesContent":["/**\n * Authentication Module\n * Exports public API for OAuth authentication only (DCR moved to ../dcr/)\n */\n\nexport { probeAuthCapabilities } from './capability-discovery.ts';\nexport { InteractiveOAuthFlow } from './interactive-oauth-flow.ts';\nexport type { OAuthCallbackListenerOptions } from './oauth-callback-listener.ts';\nexport { OAuthCallbackListener } from './oauth-callback-listener.ts';\nexport type { AuthCapabilities, CallbackResult, OAuthFlowOptions, TokenSet } from './types.ts';\n"],"names":["InteractiveOAuthFlow","OAuthCallbackListener","probeAuthCapabilities"],"mappings":"AAAA;;;CAGC;;;;;;;;;;;QAGQA;eAAAA,4CAAoB;;QAEpBC;eAAAA,8CAAqB;;
|
|
1
|
+
{"version":3,"sources":["/Users/kevin/Dev/OpenSource/ai/mcp-z/client/src/auth/index.ts"],"sourcesContent":["/**\n * Authentication Module\n * Exports public API for OAuth authentication only (DCR moved to ../dcr/)\n */\n\nexport { probeAuthCapabilities } from './capability-discovery.ts';\nexport { DiscoveryFetchError, isLoopbackUrl } from './discovery-fetch.ts';\nexport { InteractiveOAuthFlow } from './interactive-oauth-flow.ts';\nexport type { OAuthCallbackListenerOptions } from './oauth-callback-listener.ts';\nexport { OAuthCallbackListener } from './oauth-callback-listener.ts';\nexport type { AuthCapabilities, CallbackResult, OAuthFlowOptions, TokenSet } from './types.ts';\n"],"names":["DiscoveryFetchError","InteractiveOAuthFlow","OAuthCallbackListener","isLoopbackUrl","probeAuthCapabilities"],"mappings":"AAAA;;;CAGC;;;;;;;;;;;QAGQA;eAAAA,qCAAmB;;QACnBC;eAAAA,4CAAoB;;QAEpBC;eAAAA,8CAAqB;;QAHAC;eAAAA,+BAAa;;QADlCC;eAAAA,4CAAqB;;;qCAAQ;gCACa;sCACd;uCAEC"}
|
|
@@ -34,22 +34,22 @@ export declare class InteractiveOAuthFlow {
|
|
|
34
34
|
*/
|
|
35
35
|
performAuthFlow(authorizationEndpoint: string, tokenEndpoint: string, clientId: string, clientSecret: string, options: OAuthFlowOptions): Promise<TokenSet>;
|
|
36
36
|
/**
|
|
37
|
-
*
|
|
38
|
-
* @param
|
|
37
|
+
* Exchanges an authorization code for access and refresh tokens.
|
|
38
|
+
* @param allowLoopback - Loopback trust grant computed by the caller from the server it is actually talking to, never from `tokenEndpoint`.
|
|
39
|
+
* @param codeVerifier - Optional PKCE code verifier (RFC 7636).
|
|
39
40
|
*/
|
|
40
41
|
private exchangeCodeForTokens;
|
|
41
42
|
/**
|
|
42
|
-
*
|
|
43
|
-
*
|
|
44
|
-
* @param
|
|
45
|
-
* @param
|
|
46
|
-
* @param
|
|
47
|
-
* @param
|
|
48
|
-
* @returns New token set with refreshed access token
|
|
49
|
-
*
|
|
50
|
-
* @throws Error if refresh fails
|
|
43
|
+
* Refreshes an access token using a refresh token.
|
|
44
|
+
* @param tokenEndpoint - OAuth token endpoint URL.
|
|
45
|
+
* @param refreshToken - Refresh token from a previous token set.
|
|
46
|
+
* @param clientId - OAuth client ID.
|
|
47
|
+
* @param clientSecret - OAuth client secret.
|
|
48
|
+
* @param allowLoopback - Loopback trust grant computed by the caller from the server it is actually talking to, never from `tokenEndpoint`. Defaults to `false`.
|
|
49
|
+
* @returns New token set with a refreshed access token.
|
|
50
|
+
* @throws Error if refresh fails.
|
|
51
51
|
*/
|
|
52
|
-
refreshTokens(tokenEndpoint: string, refreshToken: string, clientId: string, clientSecret: string): Promise<TokenSet>;
|
|
52
|
+
refreshTokens(tokenEndpoint: string, refreshToken: string, clientId: string, clientSecret: string, allowLoopback?: boolean): Promise<TokenSet>;
|
|
53
53
|
/**
|
|
54
54
|
* Open browser to authorization URL
|
|
55
55
|
* Uses platform-specific command to open default browser
|
|
@@ -34,22 +34,22 @@ export declare class InteractiveOAuthFlow {
|
|
|
34
34
|
*/
|
|
35
35
|
performAuthFlow(authorizationEndpoint: string, tokenEndpoint: string, clientId: string, clientSecret: string, options: OAuthFlowOptions): Promise<TokenSet>;
|
|
36
36
|
/**
|
|
37
|
-
*
|
|
38
|
-
* @param
|
|
37
|
+
* Exchanges an authorization code for access and refresh tokens.
|
|
38
|
+
* @param allowLoopback - Loopback trust grant computed by the caller from the server it is actually talking to, never from `tokenEndpoint`.
|
|
39
|
+
* @param codeVerifier - Optional PKCE code verifier (RFC 7636).
|
|
39
40
|
*/
|
|
40
41
|
private exchangeCodeForTokens;
|
|
41
42
|
/**
|
|
42
|
-
*
|
|
43
|
-
*
|
|
44
|
-
* @param
|
|
45
|
-
* @param
|
|
46
|
-
* @param
|
|
47
|
-
* @param
|
|
48
|
-
* @returns New token set with refreshed access token
|
|
49
|
-
*
|
|
50
|
-
* @throws Error if refresh fails
|
|
43
|
+
* Refreshes an access token using a refresh token.
|
|
44
|
+
* @param tokenEndpoint - OAuth token endpoint URL.
|
|
45
|
+
* @param refreshToken - Refresh token from a previous token set.
|
|
46
|
+
* @param clientId - OAuth client ID.
|
|
47
|
+
* @param clientSecret - OAuth client secret.
|
|
48
|
+
* @param allowLoopback - Loopback trust grant computed by the caller from the server it is actually talking to, never from `tokenEndpoint`. Defaults to `false`.
|
|
49
|
+
* @returns New token set with a refreshed access token.
|
|
50
|
+
* @throws Error if refresh fails.
|
|
51
51
|
*/
|
|
52
|
-
refreshTokens(tokenEndpoint: string, refreshToken: string, clientId: string, clientSecret: string): Promise<TokenSet>;
|
|
52
|
+
refreshTokens(tokenEndpoint: string, refreshToken: string, clientId: string, clientSecret: string, allowLoopback?: boolean): Promise<TokenSet>;
|
|
53
53
|
/**
|
|
54
54
|
* Open browser to authorization URL
|
|
55
55
|
* Uses platform-specific command to open default browser
|
|
@@ -13,6 +13,7 @@ Object.defineProperty(exports, "InteractiveOAuthFlow", {
|
|
|
13
13
|
});
|
|
14
14
|
var _nodechild_process = /*#__PURE__*/ _interop_require_wildcard(require("node:child_process"));
|
|
15
15
|
var _loggerts = require("../utils/logger.js");
|
|
16
|
+
var _discoveryfetchts = require("./discovery-fetch.js");
|
|
16
17
|
var _oauthcallbacklistenerts = require("./oauth-callback-listener.js");
|
|
17
18
|
var _pkcets = require("./pkce.js");
|
|
18
19
|
function asyncGeneratorStep(gen, resolve, reject, _next, _throw, key, arg) {
|
|
@@ -211,7 +212,7 @@ var InteractiveOAuthFlow = /*#__PURE__*/ function() {
|
|
|
211
212
|
* );
|
|
212
213
|
*/ _proto.performAuthFlow = function performAuthFlow(authorizationEndpoint, tokenEndpoint, clientId, clientSecret, options) {
|
|
213
214
|
return _async_to_generator(function() {
|
|
214
|
-
var _options_logger, logger, callbackListener, pkce, redirectUri, authUrl, timeout, result, tokens, error;
|
|
215
|
+
var _options_logger, logger, callbackListener, pkce, _options_allowLoopback, redirectUri, authUrl, timeout, result, tokens, error;
|
|
215
216
|
return _ts_generator(this, function(_state) {
|
|
216
217
|
switch(_state.label){
|
|
217
218
|
case 0:
|
|
@@ -297,7 +298,7 @@ var InteractiveOAuthFlow = /*#__PURE__*/ function() {
|
|
|
297
298
|
result = _state.sent();
|
|
298
299
|
return [
|
|
299
300
|
4,
|
|
300
|
-
this.exchangeCodeForTokens(tokenEndpoint, result.code, clientId, clientSecret, redirectUri, pkce === null || pkce === void 0 ? void 0 : pkce.codeVerifier)
|
|
301
|
+
this.exchangeCodeForTokens(tokenEndpoint, result.code, clientId, clientSecret, redirectUri, (_options_allowLoopback = options.allowLoopback) !== null && _options_allowLoopback !== void 0 ? _options_allowLoopback : false, pkce === null || pkce === void 0 ? void 0 : pkce.codeVerifier)
|
|
301
302
|
];
|
|
302
303
|
case 8:
|
|
303
304
|
tokens = _state.sent();
|
|
@@ -329,9 +330,10 @@ var InteractiveOAuthFlow = /*#__PURE__*/ function() {
|
|
|
329
330
|
}).call(this);
|
|
330
331
|
};
|
|
331
332
|
/**
|
|
332
|
-
*
|
|
333
|
-
* @param
|
|
334
|
-
|
|
333
|
+
* Exchanges an authorization code for access and refresh tokens.
|
|
334
|
+
* @param allowLoopback - Loopback trust grant computed by the caller from the server it is actually talking to, never from `tokenEndpoint`.
|
|
335
|
+
* @param codeVerifier - Optional PKCE code verifier (RFC 7636).
|
|
336
|
+
*/ _proto.exchangeCodeForTokens = function exchangeCodeForTokens(tokenEndpoint, code, clientId, clientSecret, redirectUri, allowLoopback, codeVerifier) {
|
|
335
337
|
return _async_to_generator(function() {
|
|
336
338
|
var params, response, errorText, data, tokenSet;
|
|
337
339
|
return _ts_generator(this, function(_state) {
|
|
@@ -350,7 +352,7 @@ var InteractiveOAuthFlow = /*#__PURE__*/ function() {
|
|
|
350
352
|
}
|
|
351
353
|
return [
|
|
352
354
|
4,
|
|
353
|
-
|
|
355
|
+
(0, _discoveryfetchts.discoveryFetch)(tokenEndpoint, {
|
|
354
356
|
method: 'POST',
|
|
355
357
|
headers: {
|
|
356
358
|
'Content-Type': 'application/x-www-form-urlencoded',
|
|
@@ -358,6 +360,8 @@ var InteractiveOAuthFlow = /*#__PURE__*/ function() {
|
|
|
358
360
|
Connection: 'close'
|
|
359
361
|
},
|
|
360
362
|
body: params
|
|
363
|
+
}, 'token endpoint', {
|
|
364
|
+
allowLoopback: allowLoopback
|
|
361
365
|
})
|
|
362
366
|
];
|
|
363
367
|
case 1:
|
|
@@ -402,16 +406,16 @@ var InteractiveOAuthFlow = /*#__PURE__*/ function() {
|
|
|
402
406
|
})();
|
|
403
407
|
};
|
|
404
408
|
/**
|
|
405
|
-
*
|
|
406
|
-
*
|
|
407
|
-
* @param
|
|
408
|
-
* @param
|
|
409
|
-
* @param
|
|
410
|
-
* @param
|
|
411
|
-
* @returns New token set with refreshed access token
|
|
412
|
-
*
|
|
413
|
-
* @throws Error if refresh fails
|
|
409
|
+
* Refreshes an access token using a refresh token.
|
|
410
|
+
* @param tokenEndpoint - OAuth token endpoint URL.
|
|
411
|
+
* @param refreshToken - Refresh token from a previous token set.
|
|
412
|
+
* @param clientId - OAuth client ID.
|
|
413
|
+
* @param clientSecret - OAuth client secret.
|
|
414
|
+
* @param allowLoopback - Loopback trust grant computed by the caller from the server it is actually talking to, never from `tokenEndpoint`. Defaults to `false`.
|
|
415
|
+
* @returns New token set with a refreshed access token.
|
|
416
|
+
* @throws Error if refresh fails.
|
|
414
417
|
*/ _proto.refreshTokens = function refreshTokens(tokenEndpoint, refreshToken, clientId, clientSecret) {
|
|
418
|
+
var allowLoopback = arguments.length > 4 && arguments[4] !== void 0 ? arguments[4] : false;
|
|
415
419
|
return _async_to_generator(function() {
|
|
416
420
|
var response, errorText, data, tokenSet;
|
|
417
421
|
return _ts_generator(this, function(_state) {
|
|
@@ -419,7 +423,7 @@ var InteractiveOAuthFlow = /*#__PURE__*/ function() {
|
|
|
419
423
|
case 0:
|
|
420
424
|
return [
|
|
421
425
|
4,
|
|
422
|
-
|
|
426
|
+
(0, _discoveryfetchts.discoveryFetch)(tokenEndpoint, {
|
|
423
427
|
method: 'POST',
|
|
424
428
|
headers: {
|
|
425
429
|
'Content-Type': 'application/x-www-form-urlencoded',
|
|
@@ -432,6 +436,8 @@ var InteractiveOAuthFlow = /*#__PURE__*/ function() {
|
|
|
432
436
|
client_id: clientId,
|
|
433
437
|
client_secret: clientSecret
|
|
434
438
|
})
|
|
439
|
+
}, 'token endpoint', {
|
|
440
|
+
allowLoopback: allowLoopback
|
|
435
441
|
})
|
|
436
442
|
];
|
|
437
443
|
case 1:
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["/Users/kevin/Dev/OpenSource/ai/mcp-z/client/src/auth/interactive-oauth-flow.ts"],"sourcesContent":["/**\n * OAuth Authorization Flow Handler\n * Manages browser-based OAuth flows and token exchange with PKCE support\n */\n\nimport * as child_process from 'node:child_process';\nimport { logger as defaultLogger } from '../utils/logger.ts';\nimport { OAuthCallbackListener } from './oauth-callback-listener.ts';\nimport { generatePkce } from './pkce.ts';\nimport type { OAuthFlowOptions, PkceParams, TokenSet } from './types.ts';\n\n/**\n * OAuth token response from token endpoint\n */\ninterface TokenResponse {\n access_token: string;\n refresh_token?: string;\n expires_in: number;\n scope?: string;\n token_type?: string;\n}\n\n/**\n * InteractiveOAuthFlow manages the complete OAuth authorization code flow\n */\nexport class InteractiveOAuthFlow {\n /**\n * Perform OAuth authorization code flow\n *\n * @param authorizationEndpoint - OAuth authorization endpoint URL\n * @param tokenEndpoint - OAuth token endpoint URL\n * @param clientId - OAuth client ID\n * @param clientSecret - OAuth client secret\n * @param options - Flow options (port is required - use get-port to find available port)\n * @returns Token set with access and refresh tokens\n *\n * @throws Error if flow fails or times out\n *\n * @example\n * import getPort from 'get-port';\n *\n * const flow = new InteractiveOAuthFlow();\n * const port = await getPort();\n * const tokens = await flow.performAuthFlow(\n * 'https://example.com/oauth/authorize',\n * 'https://example.com/oauth/token',\n * 'client-id',\n * 'client-secret',\n * { port, scopes: ['read', 'write'] }\n * );\n */\n async performAuthFlow(authorizationEndpoint: string, tokenEndpoint: string, clientId: string, clientSecret: string, options: OAuthFlowOptions): Promise<TokenSet> {\n const logger = options.logger ?? defaultLogger;\n const callbackListener = new OAuthCallbackListener({ port: options.port, logger });\n\n // Generate PKCE parameters if requested (RFC 7636)\n let pkce: PkceParams | undefined;\n if (options.pkce) {\n logger.debug('🔐 Generating PKCE parameters...');\n pkce = await generatePkce();\n }\n\n try {\n // Start callback server\n await callbackListener.start();\n\n // Build redirect URI\n const redirectUri = options.redirectUri || `http://localhost:${options.port}/callback`;\n\n // Build authorization URL\n const authUrl = new URL(authorizationEndpoint);\n authUrl.searchParams.set('client_id', clientId);\n authUrl.searchParams.set('redirect_uri', redirectUri);\n authUrl.searchParams.set('response_type', 'code');\n\n if (options.scopes && options.scopes.length > 0) {\n authUrl.searchParams.set('scope', options.scopes.join(' '));\n }\n\n // Add resource parameter if specified (RFC 8707)\n if (options.resource) {\n authUrl.searchParams.set('resource', options.resource);\n }\n\n // Add PKCE parameters if generated (RFC 7636)\n if (pkce) {\n authUrl.searchParams.set('code_challenge', pkce.codeChallenge);\n authUrl.searchParams.set('code_challenge_method', pkce.codeChallengeMethod);\n }\n\n // Open browser or print URL for headless mode\n if (options.headless) {\n logger.info('🔗 Please visit this URL to authorize:');\n logger.info(authUrl.toString());\n logger.info('Waiting for callback...');\n } else {\n logger.debug('🌐 Opening browser for OAuth authorization...');\n // Try to open browser (requires 'open' package or native command)\n await this.openBrowser(authUrl.toString());\n }\n\n // Wait for callback with timeout\n const timeout = options.timeout || (options.headless ? 60000 : 300000);\n const result = await callbackListener.waitForCallback(timeout);\n\n // Exchange authorization code for tokens (with PKCE verifier if used)\n const tokens = await this.exchangeCodeForTokens(tokenEndpoint, result.code, clientId, clientSecret, redirectUri, pkce?.codeVerifier);\n\n return tokens;\n } catch (error) {\n logger.error('❌ OAuth flow failed:', error instanceof Error ? error.message : String(error));\n throw error;\n } finally {\n // Always close callback server\n await callbackListener.stop();\n }\n }\n\n /**\n * Exchange authorization code for access and refresh tokens\n * @param codeVerifier - Optional PKCE code verifier (RFC 7636)\n */\n private async exchangeCodeForTokens(tokenEndpoint: string, code: string, clientId: string, clientSecret: string, redirectUri: string, codeVerifier?: string): Promise<TokenSet> {\n const params = new URLSearchParams({\n grant_type: 'authorization_code',\n code,\n redirect_uri: redirectUri,\n client_id: clientId,\n client_secret: clientSecret,\n });\n\n // Add PKCE code verifier if provided (RFC 7636)\n if (codeVerifier) {\n params.set('code_verifier', codeVerifier);\n }\n\n const response = await fetch(tokenEndpoint, {\n method: 'POST',\n headers: {\n 'Content-Type': 'application/x-www-form-urlencoded',\n Accept: 'application/json',\n Connection: 'close',\n },\n body: params,\n });\n\n if (!response.ok) {\n const errorText = await response.text();\n throw new Error(`Token exchange failed (${response.status}): ${errorText}`);\n }\n\n const data = (await response.json()) as TokenResponse;\n\n if (!data.access_token) {\n throw new Error('Token response missing access_token');\n }\n\n const tokenSet: TokenSet = {\n accessToken: data.access_token,\n refreshToken: data.refresh_token || '',\n expiresAt: Date.now() + data.expires_in * 1000,\n clientId,\n clientSecret,\n };\n\n if (data.scope) {\n tokenSet.scopes = data.scope.split(' ');\n }\n\n return tokenSet;\n }\n\n /**\n * Refresh access token using refresh token\n *\n * @param tokenEndpoint - OAuth token endpoint URL\n * @param refreshToken - Refresh token from previous token set\n * @param clientId - OAuth client ID\n * @param clientSecret - OAuth client secret\n * @returns New token set with refreshed access token\n *\n * @throws Error if refresh fails\n */\n async refreshTokens(tokenEndpoint: string, refreshToken: string, clientId: string, clientSecret: string): Promise<TokenSet> {\n const response = await fetch(tokenEndpoint, {\n method: 'POST',\n headers: {\n 'Content-Type': 'application/x-www-form-urlencoded',\n Accept: 'application/json',\n Connection: 'close',\n },\n body: new URLSearchParams({\n grant_type: 'refresh_token',\n refresh_token: refreshToken,\n client_id: clientId,\n client_secret: clientSecret,\n }),\n });\n\n if (!response.ok) {\n const errorText = await response.text();\n throw new Error(`Token refresh failed (${response.status}): ${errorText}`);\n }\n\n const data = (await response.json()) as TokenResponse;\n\n if (!data.access_token) {\n throw new Error('Token refresh response missing access_token');\n }\n\n const tokenSet: TokenSet = {\n accessToken: data.access_token,\n refreshToken: data.refresh_token || refreshToken, // Reuse old refresh token if not provided\n expiresAt: Date.now() + data.expires_in * 1000,\n clientId,\n clientSecret,\n };\n\n if (data.scope) {\n tokenSet.scopes = data.scope.split(' ');\n }\n\n return tokenSet;\n }\n\n /**\n * Open browser to authorization URL\n * Uses platform-specific command to open default browser\n */\n private async openBrowser(url: string): Promise<void> {\n // Determine platform-specific command\n const platform = process.platform;\n let command: string;\n let args: string[];\n\n if (platform === 'darwin') {\n command = 'open';\n args = [url];\n } else if (platform === 'win32') {\n command = 'cmd';\n args = ['/c', 'start', url];\n } else {\n // Linux and others\n command = 'xdg-open';\n args = [url];\n }\n\n // Spawn browser process\n const child = child_process.spawn(command, args, {\n detached: true,\n stdio: 'ignore',\n });\n\n child.unref();\n }\n}\n"],"names":["InteractiveOAuthFlow","performAuthFlow","authorizationEndpoint","tokenEndpoint","clientId","clientSecret","options","logger","callbackListener","pkce","redirectUri","authUrl","timeout","result","tokens","error","defaultLogger","OAuthCallbackListener","port","debug","generatePkce","start","URL","searchParams","set","scopes","length","join","resource","codeChallenge","codeChallengeMethod","headless","info","toString","openBrowser","waitForCallback","exchangeCodeForTokens","code","codeVerifier","Error","message","String","stop","params","response","errorText","data","tokenSet","URLSearchParams","grant_type","redirect_uri","client_id","client_secret","fetch","method","headers","Accept","Connection","body","ok","text","status","json","access_token","accessToken","refreshToken","refresh_token","expiresAt","Date","now","expires_in","scope","split","refreshTokens","url","platform","command","args","child","process","child_process","spawn","detached","stdio","unref"],"mappings":"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"}
|
|
1
|
+
{"version":3,"sources":["/Users/kevin/Dev/OpenSource/ai/mcp-z/client/src/auth/interactive-oauth-flow.ts"],"sourcesContent":["/**\n * OAuth Authorization Flow Handler\n * Manages browser-based OAuth flows and token exchange with PKCE support\n */\n\nimport * as child_process from 'node:child_process';\nimport { logger as defaultLogger } from '../utils/logger.ts';\nimport { discoveryFetch } from './discovery-fetch.ts';\nimport { OAuthCallbackListener } from './oauth-callback-listener.ts';\nimport { generatePkce } from './pkce.ts';\nimport type { OAuthFlowOptions, PkceParams, TokenSet } from './types.ts';\n\n/**\n * OAuth token response from token endpoint\n */\ninterface TokenResponse {\n access_token: string;\n refresh_token?: string;\n expires_in: number;\n scope?: string;\n token_type?: string;\n}\n\n/**\n * InteractiveOAuthFlow manages the complete OAuth authorization code flow\n */\nexport class InteractiveOAuthFlow {\n /**\n * Perform OAuth authorization code flow\n *\n * @param authorizationEndpoint - OAuth authorization endpoint URL\n * @param tokenEndpoint - OAuth token endpoint URL\n * @param clientId - OAuth client ID\n * @param clientSecret - OAuth client secret\n * @param options - Flow options (port is required - use get-port to find available port)\n * @returns Token set with access and refresh tokens\n *\n * @throws Error if flow fails or times out\n *\n * @example\n * import getPort from 'get-port';\n *\n * const flow = new InteractiveOAuthFlow();\n * const port = await getPort();\n * const tokens = await flow.performAuthFlow(\n * 'https://example.com/oauth/authorize',\n * 'https://example.com/oauth/token',\n * 'client-id',\n * 'client-secret',\n * { port, scopes: ['read', 'write'] }\n * );\n */\n async performAuthFlow(authorizationEndpoint: string, tokenEndpoint: string, clientId: string, clientSecret: string, options: OAuthFlowOptions): Promise<TokenSet> {\n const logger = options.logger ?? defaultLogger;\n const callbackListener = new OAuthCallbackListener({ port: options.port, logger });\n\n // Generate PKCE parameters if requested (RFC 7636)\n let pkce: PkceParams | undefined;\n if (options.pkce) {\n logger.debug('🔐 Generating PKCE parameters...');\n pkce = await generatePkce();\n }\n\n try {\n // Start callback server\n await callbackListener.start();\n\n // Build redirect URI\n const redirectUri = options.redirectUri || `http://localhost:${options.port}/callback`;\n\n // Build authorization URL\n const authUrl = new URL(authorizationEndpoint);\n authUrl.searchParams.set('client_id', clientId);\n authUrl.searchParams.set('redirect_uri', redirectUri);\n authUrl.searchParams.set('response_type', 'code');\n\n if (options.scopes && options.scopes.length > 0) {\n authUrl.searchParams.set('scope', options.scopes.join(' '));\n }\n\n // Add resource parameter if specified (RFC 8707)\n if (options.resource) {\n authUrl.searchParams.set('resource', options.resource);\n }\n\n // Add PKCE parameters if generated (RFC 7636)\n if (pkce) {\n authUrl.searchParams.set('code_challenge', pkce.codeChallenge);\n authUrl.searchParams.set('code_challenge_method', pkce.codeChallengeMethod);\n }\n\n // Open browser or print URL for headless mode\n if (options.headless) {\n logger.info('🔗 Please visit this URL to authorize:');\n logger.info(authUrl.toString());\n logger.info('Waiting for callback...');\n } else {\n logger.debug('🌐 Opening browser for OAuth authorization...');\n // Try to open browser (requires 'open' package or native command)\n await this.openBrowser(authUrl.toString());\n }\n\n // Wait for callback with timeout\n const timeout = options.timeout || (options.headless ? 60000 : 300000);\n const result = await callbackListener.waitForCallback(timeout);\n\n // Exchange authorization code for tokens (with PKCE verifier if used)\n const tokens = await this.exchangeCodeForTokens(tokenEndpoint, result.code, clientId, clientSecret, redirectUri, options.allowLoopback ?? false, pkce?.codeVerifier);\n\n return tokens;\n } catch (error) {\n logger.error('❌ OAuth flow failed:', error instanceof Error ? error.message : String(error));\n throw error;\n } finally {\n // Always close callback server\n await callbackListener.stop();\n }\n }\n\n /**\n * Exchanges an authorization code for access and refresh tokens.\n * @param allowLoopback - Loopback trust grant computed by the caller from the server it is actually talking to, never from `tokenEndpoint`.\n * @param codeVerifier - Optional PKCE code verifier (RFC 7636).\n */\n private async exchangeCodeForTokens(tokenEndpoint: string, code: string, clientId: string, clientSecret: string, redirectUri: string, allowLoopback: boolean, codeVerifier?: string): Promise<TokenSet> {\n const params = new URLSearchParams({\n grant_type: 'authorization_code',\n code,\n redirect_uri: redirectUri,\n client_id: clientId,\n client_secret: clientSecret,\n });\n\n // Add PKCE code verifier if provided (RFC 7636)\n if (codeVerifier) {\n params.set('code_verifier', codeVerifier);\n }\n\n // tokenEndpoint is remote-controlled discovery data; discoveryFetch blocks\n // a private/internal target before the client secret is sent to it.\n const response = await discoveryFetch(\n tokenEndpoint,\n {\n method: 'POST',\n headers: {\n 'Content-Type': 'application/x-www-form-urlencoded',\n Accept: 'application/json',\n Connection: 'close',\n },\n body: params,\n },\n 'token endpoint',\n { allowLoopback }\n );\n\n if (!response.ok) {\n const errorText = await response.text();\n throw new Error(`Token exchange failed (${response.status}): ${errorText}`);\n }\n\n const data = (await response.json()) as TokenResponse;\n\n if (!data.access_token) {\n throw new Error('Token response missing access_token');\n }\n\n const tokenSet: TokenSet = {\n accessToken: data.access_token,\n refreshToken: data.refresh_token || '',\n expiresAt: Date.now() + data.expires_in * 1000,\n clientId,\n clientSecret,\n };\n\n if (data.scope) {\n tokenSet.scopes = data.scope.split(' ');\n }\n\n return tokenSet;\n }\n\n /**\n * Refreshes an access token using a refresh token.\n * @param tokenEndpoint - OAuth token endpoint URL.\n * @param refreshToken - Refresh token from a previous token set.\n * @param clientId - OAuth client ID.\n * @param clientSecret - OAuth client secret.\n * @param allowLoopback - Loopback trust grant computed by the caller from the server it is actually talking to, never from `tokenEndpoint`. Defaults to `false`.\n * @returns New token set with a refreshed access token.\n * @throws Error if refresh fails.\n */\n async refreshTokens(tokenEndpoint: string, refreshToken: string, clientId: string, clientSecret: string, allowLoopback = false): Promise<TokenSet> {\n // See exchangeCodeForTokens - tokenEndpoint is remote-controlled discovery data.\n const response = await discoveryFetch(\n tokenEndpoint,\n {\n method: 'POST',\n headers: {\n 'Content-Type': 'application/x-www-form-urlencoded',\n Accept: 'application/json',\n Connection: 'close',\n },\n body: new URLSearchParams({\n grant_type: 'refresh_token',\n refresh_token: refreshToken,\n client_id: clientId,\n client_secret: clientSecret,\n }),\n },\n 'token endpoint',\n { allowLoopback }\n );\n\n if (!response.ok) {\n const errorText = await response.text();\n throw new Error(`Token refresh failed (${response.status}): ${errorText}`);\n }\n\n const data = (await response.json()) as TokenResponse;\n\n if (!data.access_token) {\n throw new Error('Token refresh response missing access_token');\n }\n\n const tokenSet: TokenSet = {\n accessToken: data.access_token,\n refreshToken: data.refresh_token || refreshToken, // Reuse old refresh token if not provided\n expiresAt: Date.now() + data.expires_in * 1000,\n clientId,\n clientSecret,\n };\n\n if (data.scope) {\n tokenSet.scopes = data.scope.split(' ');\n }\n\n return tokenSet;\n }\n\n /**\n * Open browser to authorization URL\n * Uses platform-specific command to open default browser\n */\n private async openBrowser(url: string): Promise<void> {\n // Determine platform-specific command\n const platform = process.platform;\n let command: string;\n let args: string[];\n\n if (platform === 'darwin') {\n command = 'open';\n args = [url];\n } else if (platform === 'win32') {\n command = 'cmd';\n args = ['/c', 'start', url];\n } else {\n // Linux and others\n command = 'xdg-open';\n args = [url];\n }\n\n // Spawn browser process\n const child = child_process.spawn(command, args, {\n detached: true,\n stdio: 'ignore',\n });\n\n child.unref();\n }\n}\n"],"names":["InteractiveOAuthFlow","performAuthFlow","authorizationEndpoint","tokenEndpoint","clientId","clientSecret","options","logger","callbackListener","pkce","redirectUri","authUrl","timeout","result","tokens","error","defaultLogger","OAuthCallbackListener","port","debug","generatePkce","start","URL","searchParams","set","scopes","length","join","resource","codeChallenge","codeChallengeMethod","headless","info","toString","openBrowser","waitForCallback","exchangeCodeForTokens","code","allowLoopback","codeVerifier","Error","message","String","stop","params","response","errorText","data","tokenSet","URLSearchParams","grant_type","redirect_uri","client_id","client_secret","discoveryFetch","method","headers","Accept","Connection","body","ok","text","status","json","access_token","accessToken","refreshToken","refresh_token","expiresAt","Date","now","expires_in","scope","split","refreshTokens","url","platform","command","args","child","process","child_process","spawn","detached","stdio","unref"],"mappings":"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"}
|
|
@@ -4,37 +4,24 @@
|
|
|
4
4
|
*/
|
|
5
5
|
import type { AuthorizationServerMetadata, ProtectedResourceMetadata } from './types.js';
|
|
6
6
|
/**
|
|
7
|
-
*
|
|
8
|
-
|
|
9
|
-
/**
|
|
10
|
-
* Discover OAuth 2.0 Protected Resource Metadata (RFC 9728)
|
|
11
|
-
* Probes .well-known/oauth-protected-resource endpoint
|
|
7
|
+
* Discovers RFC 9728 Protected Resource Metadata: the `WWW-Authenticate`
|
|
8
|
+
* header first, then `.well-known/oauth-protected-resource` at the origin root and, for a path-prefixed resource, its sub-path variant.
|
|
12
9
|
*
|
|
13
|
-
*
|
|
14
|
-
*
|
|
15
|
-
* 2. If 404, try sub-path: {origin}/.well-known/oauth-protected-resource{path}
|
|
16
|
-
*
|
|
17
|
-
* @param resourceUrl - URL of the protected resource (e.g., https://ai.todoist.net/mcp)
|
|
18
|
-
* @returns ProtectedResourceMetadata if discovered, null otherwise
|
|
19
|
-
*
|
|
20
|
-
* @example
|
|
21
|
-
* // Todoist case: MCP at ai.todoist.net/mcp, OAuth at todoist.com
|
|
22
|
-
* const metadata = await discoverProtectedResourceMetadata('https://ai.todoist.net/mcp');
|
|
23
|
-
* // Returns: { resource: "https://ai.todoist.net/mcp", authorization_servers: ["https://todoist.com"] }
|
|
10
|
+
* @param resourceUrl - URL of the protected resource (e.g. `https://ai.todoist.net/mcp`).
|
|
11
|
+
* @returns Discovered metadata, or `null` if none is found.
|
|
24
12
|
*/
|
|
25
13
|
export declare function discoverProtectedResourceMetadata(resourceUrl: string): Promise<ProtectedResourceMetadata | null>;
|
|
26
14
|
/**
|
|
27
|
-
*
|
|
28
|
-
*
|
|
29
|
-
*
|
|
30
|
-
* @param authServerUrl - URL of the authorization server (typically from RFC 9728 discovery)
|
|
31
|
-
* @returns AuthorizationServerMetadata if discovered, null otherwise
|
|
15
|
+
* Discovers RFC 8414 Authorization Server Metadata at
|
|
16
|
+
* `.well-known/oauth-authorization-server`, path-local variant first.
|
|
32
17
|
*
|
|
33
|
-
* @
|
|
34
|
-
*
|
|
35
|
-
*
|
|
18
|
+
* @param authServerUrl - URL of the authorization server (typically from RFC 9728 discovery).
|
|
19
|
+
* @param options.allowLoopback - Loopback trust grant computed from the server the caller is actually talking to, never from `authServerUrl` itself. Defaults to `false`.
|
|
20
|
+
* @returns Discovered metadata, or `null` if none is found.
|
|
36
21
|
*/
|
|
37
|
-
export declare function discoverAuthorizationServerMetadata(authServerUrl: string
|
|
22
|
+
export declare function discoverAuthorizationServerMetadata(authServerUrl: string, options?: {
|
|
23
|
+
allowLoopback?: boolean;
|
|
24
|
+
}): Promise<AuthorizationServerMetadata | null>;
|
|
38
25
|
/**
|
|
39
26
|
* Discover OAuth Authorization Server Issuer from resource response (RFC 9207)
|
|
40
27
|
*
|
|
@@ -4,37 +4,24 @@
|
|
|
4
4
|
*/
|
|
5
5
|
import type { AuthorizationServerMetadata, ProtectedResourceMetadata } from './types.js';
|
|
6
6
|
/**
|
|
7
|
-
*
|
|
8
|
-
|
|
9
|
-
/**
|
|
10
|
-
* Discover OAuth 2.0 Protected Resource Metadata (RFC 9728)
|
|
11
|
-
* Probes .well-known/oauth-protected-resource endpoint
|
|
7
|
+
* Discovers RFC 9728 Protected Resource Metadata: the `WWW-Authenticate`
|
|
8
|
+
* header first, then `.well-known/oauth-protected-resource` at the origin root and, for a path-prefixed resource, its sub-path variant.
|
|
12
9
|
*
|
|
13
|
-
*
|
|
14
|
-
*
|
|
15
|
-
* 2. If 404, try sub-path: {origin}/.well-known/oauth-protected-resource{path}
|
|
16
|
-
*
|
|
17
|
-
* @param resourceUrl - URL of the protected resource (e.g., https://ai.todoist.net/mcp)
|
|
18
|
-
* @returns ProtectedResourceMetadata if discovered, null otherwise
|
|
19
|
-
*
|
|
20
|
-
* @example
|
|
21
|
-
* // Todoist case: MCP at ai.todoist.net/mcp, OAuth at todoist.com
|
|
22
|
-
* const metadata = await discoverProtectedResourceMetadata('https://ai.todoist.net/mcp');
|
|
23
|
-
* // Returns: { resource: "https://ai.todoist.net/mcp", authorization_servers: ["https://todoist.com"] }
|
|
10
|
+
* @param resourceUrl - URL of the protected resource (e.g. `https://ai.todoist.net/mcp`).
|
|
11
|
+
* @returns Discovered metadata, or `null` if none is found.
|
|
24
12
|
*/
|
|
25
13
|
export declare function discoverProtectedResourceMetadata(resourceUrl: string): Promise<ProtectedResourceMetadata | null>;
|
|
26
14
|
/**
|
|
27
|
-
*
|
|
28
|
-
*
|
|
29
|
-
*
|
|
30
|
-
* @param authServerUrl - URL of the authorization server (typically from RFC 9728 discovery)
|
|
31
|
-
* @returns AuthorizationServerMetadata if discovered, null otherwise
|
|
15
|
+
* Discovers RFC 8414 Authorization Server Metadata at
|
|
16
|
+
* `.well-known/oauth-authorization-server`, path-local variant first.
|
|
32
17
|
*
|
|
33
|
-
* @
|
|
34
|
-
*
|
|
35
|
-
*
|
|
18
|
+
* @param authServerUrl - URL of the authorization server (typically from RFC 9728 discovery).
|
|
19
|
+
* @param options.allowLoopback - Loopback trust grant computed from the server the caller is actually talking to, never from `authServerUrl` itself. Defaults to `false`.
|
|
20
|
+
* @returns Discovered metadata, or `null` if none is found.
|
|
36
21
|
*/
|
|
37
|
-
export declare function discoverAuthorizationServerMetadata(authServerUrl: string
|
|
22
|
+
export declare function discoverAuthorizationServerMetadata(authServerUrl: string, options?: {
|
|
23
|
+
allowLoopback?: boolean;
|
|
24
|
+
}): Promise<AuthorizationServerMetadata | null>;
|
|
38
25
|
/**
|
|
39
26
|
* Discover OAuth Authorization Server Issuer from resource response (RFC 9207)
|
|
40
27
|
*
|