@apify/mcpc 0.1.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/.claude/settings.local.json +36 -0
- package/.eslintrc.json +44 -0
- package/.idea/codeStyles/Project.xml +60 -0
- package/.idea/codeStyles/codeStyleConfig.xml +5 -0
- package/.idea/inspectionProfiles/Project_Default.xml +11 -0
- package/.idea/prettier.xml +6 -0
- package/.idea/vcs.xml +6 -0
- package/.idea/workspace.xml +572 -0
- package/LICENSE +201 -0
- package/PHASE1-SUMMARY.md +269 -0
- package/PUBLISHING.md +111 -0
- package/README.md +1056 -0
- package/TESTING.md +212 -0
- package/TODOs.md +94 -0
- package/bin/mcpc +9 -0
- package/bin/mcpc-bridge +9 -0
- package/dist/bridge/index.d.ts +3 -0
- package/dist/bridge/index.d.ts.map +1 -0
- package/dist/bridge/index.js +587 -0
- package/dist/bridge/index.js.map +1 -0
- package/dist/cli/commands/auth.d.ts +9 -0
- package/dist/cli/commands/auth.d.ts.map +1 -0
- package/dist/cli/commands/auth.js +81 -0
- package/dist/cli/commands/auth.js.map +1 -0
- package/dist/cli/commands/clean.d.ts +11 -0
- package/dist/cli/commands/clean.d.ts.map +1 -0
- package/dist/cli/commands/clean.js +224 -0
- package/dist/cli/commands/clean.js.map +1 -0
- package/dist/cli/commands/index.d.ts +8 -0
- package/dist/cli/commands/index.d.ts.map +1 -0
- package/dist/cli/commands/index.js +8 -0
- package/dist/cli/commands/index.js.map +1 -0
- package/dist/cli/commands/logging.d.ts +3 -0
- package/dist/cli/commands/logging.d.ts.map +1 -0
- package/dist/cli/commands/logging.js +22 -0
- package/dist/cli/commands/logging.js.map +1 -0
- package/dist/cli/commands/prompts.d.ts +6 -0
- package/dist/cli/commands/prompts.d.ts.map +1 -0
- package/dist/cli/commands/prompts.js +27 -0
- package/dist/cli/commands/prompts.js.map +1 -0
- package/dist/cli/commands/resources.d.ts +11 -0
- package/dist/cli/commands/resources.d.ts.map +1 -0
- package/dist/cli/commands/resources.js +70 -0
- package/dist/cli/commands/resources.js.map +1 -0
- package/dist/cli/commands/sessions.d.ts +28 -0
- package/dist/cli/commands/sessions.d.ts.map +1 -0
- package/dist/cli/commands/sessions.js +356 -0
- package/dist/cli/commands/sessions.js.map +1 -0
- package/dist/cli/commands/tools.d.ts +8 -0
- package/dist/cli/commands/tools.d.ts.map +1 -0
- package/dist/cli/commands/tools.js +54 -0
- package/dist/cli/commands/tools.js.map +1 -0
- package/dist/cli/commands/utilities.d.ts +3 -0
- package/dist/cli/commands/utilities.d.ts.map +1 -0
- package/dist/cli/commands/utilities.js +20 -0
- package/dist/cli/commands/utilities.js.map +1 -0
- package/dist/cli/helpers.d.ts +18 -0
- package/dist/cli/helpers.d.ts.map +1 -0
- package/dist/cli/helpers.js +165 -0
- package/dist/cli/helpers.js.map +1 -0
- package/dist/cli/index.d.ts +3 -0
- package/dist/cli/index.d.ts.map +1 -0
- package/dist/cli/index.js +326 -0
- package/dist/cli/index.js.map +1 -0
- package/dist/cli/output.d.ts +18 -0
- package/dist/cli/output.d.ts.map +1 -0
- package/dist/cli/output.js +221 -0
- package/dist/cli/output.js.map +1 -0
- package/dist/cli/parser.d.ts +19 -0
- package/dist/cli/parser.d.ts.map +1 -0
- package/dist/cli/parser.js +168 -0
- package/dist/cli/parser.js.map +1 -0
- package/dist/cli/shell-parser.d.ts +5 -0
- package/dist/cli/shell-parser.d.ts.map +1 -0
- package/dist/cli/shell-parser.js +38 -0
- package/dist/cli/shell-parser.js.map +1 -0
- package/dist/cli/shell.d.ts +2 -0
- package/dist/cli/shell.d.ts.map +1 -0
- package/dist/cli/shell.js +277 -0
- package/dist/cli/shell.js.map +1 -0
- package/dist/cli/tool-result.d.ts +2 -0
- package/dist/cli/tool-result.d.ts.map +1 -0
- package/dist/cli/tool-result.js +19 -0
- package/dist/cli/tool-result.js.map +1 -0
- package/dist/core/factory.d.ts +19 -0
- package/dist/core/factory.d.ts.map +1 -0
- package/dist/core/factory.js +55 -0
- package/dist/core/factory.js.map +1 -0
- package/dist/core/index.d.ts +4 -0
- package/dist/core/index.d.ts.map +1 -0
- package/dist/core/index.js +4 -0
- package/dist/core/index.js.map +1 -0
- package/dist/core/mcp-client.d.ts +30 -0
- package/dist/core/mcp-client.d.ts.map +1 -0
- package/dist/core/mcp-client.js +215 -0
- package/dist/core/mcp-client.js.map +1 -0
- package/dist/core/transports.d.ts +12 -0
- package/dist/core/transports.d.ts.map +1 -0
- package/dist/core/transports.js +65 -0
- package/dist/core/transports.js.map +1 -0
- package/dist/lib/auth/auth-profiles.d.ts +7 -0
- package/dist/lib/auth/auth-profiles.d.ts.map +1 -0
- package/dist/lib/auth/auth-profiles.js +105 -0
- package/dist/lib/auth/auth-profiles.js.map +1 -0
- package/dist/lib/auth/keychain.d.ts +22 -0
- package/dist/lib/auth/keychain.d.ts.map +1 -0
- package/dist/lib/auth/keychain.js +92 -0
- package/dist/lib/auth/keychain.js.map +1 -0
- package/dist/lib/auth/oauth-flow.d.ts +7 -0
- package/dist/lib/auth/oauth-flow.d.ts.map +1 -0
- package/dist/lib/auth/oauth-flow.js +236 -0
- package/dist/lib/auth/oauth-flow.js.map +1 -0
- package/dist/lib/auth/oauth-provider.d.ts +24 -0
- package/dist/lib/auth/oauth-provider.d.ts.map +1 -0
- package/dist/lib/auth/oauth-provider.js +144 -0
- package/dist/lib/auth/oauth-provider.js.map +1 -0
- package/dist/lib/auth/oauth-token-manager.d.ts +25 -0
- package/dist/lib/auth/oauth-token-manager.d.ts.map +1 -0
- package/dist/lib/auth/oauth-token-manager.js +70 -0
- package/dist/lib/auth/oauth-token-manager.js.map +1 -0
- package/dist/lib/auth/oauth-utils.d.ts +14 -0
- package/dist/lib/auth/oauth-utils.d.ts.map +1 -0
- package/dist/lib/auth/oauth-utils.js +68 -0
- package/dist/lib/auth/oauth-utils.js.map +1 -0
- package/dist/lib/auth/token-refresh.d.ts +2 -0
- package/dist/lib/auth/token-refresh.d.ts.map +1 -0
- package/dist/lib/auth/token-refresh.js +70 -0
- package/dist/lib/auth/token-refresh.js.map +1 -0
- package/dist/lib/bridge-client.d.ts +23 -0
- package/dist/lib/bridge-client.d.ts.map +1 -0
- package/dist/lib/bridge-client.js +181 -0
- package/dist/lib/bridge-client.js.map +1 -0
- package/dist/lib/bridge-manager.d.ts +17 -0
- package/dist/lib/bridge-manager.d.ts.map +1 -0
- package/dist/lib/bridge-manager.js +240 -0
- package/dist/lib/bridge-manager.js.map +1 -0
- package/dist/lib/config.d.ts +6 -0
- package/dist/lib/config.d.ts.map +1 -0
- package/dist/lib/config.js +116 -0
- package/dist/lib/config.js.map +1 -0
- package/dist/lib/errors.d.ts +23 -0
- package/dist/lib/errors.d.ts.map +1 -0
- package/dist/lib/errors.js +81 -0
- package/dist/lib/errors.js.map +1 -0
- package/dist/lib/file-lock.d.ts +2 -0
- package/dist/lib/file-lock.d.ts.map +1 -0
- package/dist/lib/file-lock.js +46 -0
- package/dist/lib/file-lock.js.map +1 -0
- package/dist/lib/file-logger.d.ts +19 -0
- package/dist/lib/file-logger.d.ts.map +1 -0
- package/dist/lib/file-logger.js +126 -0
- package/dist/lib/file-logger.js.map +1 -0
- package/dist/lib/index.d.ts +6 -0
- package/dist/lib/index.d.ts.map +1 -0
- package/dist/lib/index.js +6 -0
- package/dist/lib/index.js.map +1 -0
- package/dist/lib/logger.d.ts +24 -0
- package/dist/lib/logger.d.ts.map +1 -0
- package/dist/lib/logger.js +189 -0
- package/dist/lib/logger.js.map +1 -0
- package/dist/lib/session-client.d.ts +28 -0
- package/dist/lib/session-client.d.ts.map +1 -0
- package/dist/lib/session-client.js +104 -0
- package/dist/lib/session-client.js.map +1 -0
- package/dist/lib/sessions.d.ts +9 -0
- package/dist/lib/sessions.d.ts.map +1 -0
- package/dist/lib/sessions.js +116 -0
- package/dist/lib/sessions.js.map +1 -0
- package/dist/lib/types.d.ts +117 -0
- package/dist/lib/types.d.ts.map +1 -0
- package/dist/lib/types.js +2 -0
- package/dist/lib/types.js.map +1 -0
- package/dist/lib/utils.d.ts +29 -0
- package/dist/lib/utils.d.ts.map +1 -0
- package/dist/lib/utils.js +173 -0
- package/dist/lib/utils.js.map +1 -0
- package/package.json +71 -0
- package/tsconfig.test.json +11 -0
|
@@ -0,0 +1,236 @@
|
|
|
1
|
+
import { createServer } from 'http';
|
|
2
|
+
import { URL } from 'url';
|
|
3
|
+
import { auth as sdkAuth } from '@modelcontextprotocol/sdk/client/auth.js';
|
|
4
|
+
import { McpcOAuthProvider } from './oauth-provider.js';
|
|
5
|
+
import { normalizeServerUrl } from '../utils.js';
|
|
6
|
+
import { ClientError } from '../errors.js';
|
|
7
|
+
import { createLogger } from '../logger.js';
|
|
8
|
+
const logger = createLogger('oauth-flow');
|
|
9
|
+
const ESCAPE_KEY = '\x1b';
|
|
10
|
+
function waitForEscapeKey() {
|
|
11
|
+
let cleanup = () => { };
|
|
12
|
+
let cleaned = false;
|
|
13
|
+
const promise = new Promise((_resolve, reject) => {
|
|
14
|
+
if (!process.stdin.isTTY) {
|
|
15
|
+
return;
|
|
16
|
+
}
|
|
17
|
+
const onData = (key) => {
|
|
18
|
+
if (key.toString() === ESCAPE_KEY) {
|
|
19
|
+
reject(new ClientError('Authentication cancelled by user'));
|
|
20
|
+
}
|
|
21
|
+
};
|
|
22
|
+
process.stdin.setRawMode(true);
|
|
23
|
+
process.stdin.resume();
|
|
24
|
+
process.stdin.on('data', onData);
|
|
25
|
+
cleanup = () => {
|
|
26
|
+
if (cleaned)
|
|
27
|
+
return;
|
|
28
|
+
cleaned = true;
|
|
29
|
+
process.stdin.off('data', onData);
|
|
30
|
+
process.stdin.setRawMode(false);
|
|
31
|
+
process.stdin.pause();
|
|
32
|
+
};
|
|
33
|
+
});
|
|
34
|
+
return { promise, cleanup };
|
|
35
|
+
}
|
|
36
|
+
function startCallbackServer(port) {
|
|
37
|
+
let resolveCode;
|
|
38
|
+
let rejectCode;
|
|
39
|
+
const codePromise = new Promise((resolve, reject) => {
|
|
40
|
+
resolveCode = resolve;
|
|
41
|
+
rejectCode = reject;
|
|
42
|
+
});
|
|
43
|
+
const sockets = new Set();
|
|
44
|
+
const server = createServer((req, res) => {
|
|
45
|
+
const url = new URL(req.url || '/', `http://localhost:${port}`);
|
|
46
|
+
if (url.pathname === '/callback') {
|
|
47
|
+
const code = url.searchParams.get('code');
|
|
48
|
+
const error = url.searchParams.get('error');
|
|
49
|
+
const errorDescription = url.searchParams.get('error_description');
|
|
50
|
+
const state = url.searchParams.get('state') || undefined;
|
|
51
|
+
if (error) {
|
|
52
|
+
const message = errorDescription || error;
|
|
53
|
+
res.writeHead(400, { 'Content-Type': 'text/html' });
|
|
54
|
+
res.end(`
|
|
55
|
+
<html>
|
|
56
|
+
<head><title>Authentication failed</title></head>
|
|
57
|
+
<body>
|
|
58
|
+
<h1>Authentication failed</h1>
|
|
59
|
+
<p>Error: ${message}</p>
|
|
60
|
+
<p>You can close this window.</p>
|
|
61
|
+
</body>
|
|
62
|
+
</html>
|
|
63
|
+
`);
|
|
64
|
+
rejectCode(new ClientError(`OAuth error: ${message}`));
|
|
65
|
+
return;
|
|
66
|
+
}
|
|
67
|
+
if (!code) {
|
|
68
|
+
res.writeHead(400, { 'Content-Type': 'text/html' });
|
|
69
|
+
res.end(`
|
|
70
|
+
<html>
|
|
71
|
+
<head><title>Authentication failed</title></head>
|
|
72
|
+
<body>
|
|
73
|
+
<h1>Authentication failed</h1>
|
|
74
|
+
<p>No authorization code received</p>
|
|
75
|
+
<p>You can close this window.</p>
|
|
76
|
+
</body>
|
|
77
|
+
</html>
|
|
78
|
+
`);
|
|
79
|
+
rejectCode(new ClientError('No authorization code in callback'));
|
|
80
|
+
return;
|
|
81
|
+
}
|
|
82
|
+
res.writeHead(200, { 'Content-Type': 'text/html' });
|
|
83
|
+
res.end(`
|
|
84
|
+
<html>
|
|
85
|
+
<head><title>Authentication successful</title></head>
|
|
86
|
+
<body>
|
|
87
|
+
<h1>Authentication successful!</h1>
|
|
88
|
+
<p>You can close this window and return to the terminal.</p>
|
|
89
|
+
</body>
|
|
90
|
+
</html>
|
|
91
|
+
`);
|
|
92
|
+
const result = { code };
|
|
93
|
+
if (state !== undefined) {
|
|
94
|
+
result.state = state;
|
|
95
|
+
}
|
|
96
|
+
resolveCode(result);
|
|
97
|
+
}
|
|
98
|
+
else {
|
|
99
|
+
res.writeHead(404);
|
|
100
|
+
res.end('Not found');
|
|
101
|
+
}
|
|
102
|
+
});
|
|
103
|
+
server.on('connection', (socket) => {
|
|
104
|
+
sockets.add(socket);
|
|
105
|
+
socket.on('close', () => {
|
|
106
|
+
sockets.delete(socket);
|
|
107
|
+
});
|
|
108
|
+
});
|
|
109
|
+
const destroyConnections = () => {
|
|
110
|
+
for (const socket of sockets) {
|
|
111
|
+
socket.destroy();
|
|
112
|
+
}
|
|
113
|
+
sockets.clear();
|
|
114
|
+
};
|
|
115
|
+
return { server, codePromise, destroyConnections };
|
|
116
|
+
}
|
|
117
|
+
async function findAvailablePort(startPort = 8000) {
|
|
118
|
+
for (let port = startPort; port < startPort + 100; port++) {
|
|
119
|
+
try {
|
|
120
|
+
await new Promise((resolve, reject) => {
|
|
121
|
+
const testServer = createServer();
|
|
122
|
+
testServer.once('error', reject);
|
|
123
|
+
testServer.once('listening', () => {
|
|
124
|
+
testServer.close(() => resolve());
|
|
125
|
+
});
|
|
126
|
+
testServer.listen(port, '127.0.0.1');
|
|
127
|
+
});
|
|
128
|
+
return port;
|
|
129
|
+
}
|
|
130
|
+
catch {
|
|
131
|
+
}
|
|
132
|
+
}
|
|
133
|
+
throw new ClientError('Could not find available port for OAuth callback server');
|
|
134
|
+
}
|
|
135
|
+
async function openBrowser(url) {
|
|
136
|
+
const { exec } = await import('child_process');
|
|
137
|
+
const { promisify } = await import('util');
|
|
138
|
+
const execAsync = promisify(exec);
|
|
139
|
+
const platform = process.platform;
|
|
140
|
+
let command;
|
|
141
|
+
if (platform === 'darwin') {
|
|
142
|
+
command = `open "${url}"`;
|
|
143
|
+
}
|
|
144
|
+
else if (platform === 'win32') {
|
|
145
|
+
command = `start "${url}"`;
|
|
146
|
+
}
|
|
147
|
+
else {
|
|
148
|
+
command = `xdg-open "${url}"`;
|
|
149
|
+
}
|
|
150
|
+
try {
|
|
151
|
+
await execAsync(command);
|
|
152
|
+
logger.debug('Browser opened successfully');
|
|
153
|
+
}
|
|
154
|
+
catch (error) {
|
|
155
|
+
logger.warn(`Failed to open browser: ${error.message}`);
|
|
156
|
+
throw new ClientError(`Failed to open browser. Please manually navigate to: ${url}`);
|
|
157
|
+
}
|
|
158
|
+
}
|
|
159
|
+
export async function performOAuthFlow(serverUrl, profileName, scope) {
|
|
160
|
+
logger.debug(`Starting OAuth flow for ${serverUrl} (profile: ${profileName})`);
|
|
161
|
+
const normalizedServerUrl = normalizeServerUrl(serverUrl);
|
|
162
|
+
const port = await findAvailablePort(8000);
|
|
163
|
+
const redirectUrl = `http://localhost:${port}/callback`;
|
|
164
|
+
logger.debug(`Using redirect URL: ${redirectUrl}`);
|
|
165
|
+
const provider = new McpcOAuthProvider(normalizedServerUrl, profileName, redirectUrl, true);
|
|
166
|
+
const { server, codePromise, destroyConnections } = startCallbackServer(port);
|
|
167
|
+
try {
|
|
168
|
+
await new Promise((resolve, reject) => {
|
|
169
|
+
server.once('error', reject);
|
|
170
|
+
server.listen(port, '127.0.0.1', () => {
|
|
171
|
+
logger.debug(`Callback server listening on port ${port}`);
|
|
172
|
+
resolve();
|
|
173
|
+
});
|
|
174
|
+
});
|
|
175
|
+
provider.redirectToAuthorization = async (authorizationUrl) => {
|
|
176
|
+
logger.debug('Opening browser for authorization...');
|
|
177
|
+
console.log(`\nOpening browser to: ${authorizationUrl.toString()}`);
|
|
178
|
+
console.log('If the browser does not open automatically, please visit the URL above.');
|
|
179
|
+
console.log('Press Esc to cancel.\n');
|
|
180
|
+
try {
|
|
181
|
+
await openBrowser(authorizationUrl.toString());
|
|
182
|
+
}
|
|
183
|
+
catch (error) {
|
|
184
|
+
console.error(error.message);
|
|
185
|
+
}
|
|
186
|
+
};
|
|
187
|
+
const escapeHandler = waitForEscapeKey();
|
|
188
|
+
try {
|
|
189
|
+
logger.debug('Calling SDK auth()...');
|
|
190
|
+
const authOptions = {
|
|
191
|
+
serverUrl: normalizedServerUrl,
|
|
192
|
+
};
|
|
193
|
+
if (scope !== undefined) {
|
|
194
|
+
authOptions.scope = scope;
|
|
195
|
+
}
|
|
196
|
+
const result = await sdkAuth(provider, authOptions);
|
|
197
|
+
if (result === 'REDIRECT') {
|
|
198
|
+
logger.debug('Waiting for authorization code...');
|
|
199
|
+
const { code } = await Promise.race([
|
|
200
|
+
codePromise,
|
|
201
|
+
escapeHandler.promise,
|
|
202
|
+
]);
|
|
203
|
+
logger.debug('Exchanging authorization code for tokens...');
|
|
204
|
+
const tokenOptions = {
|
|
205
|
+
serverUrl: normalizedServerUrl,
|
|
206
|
+
authorizationCode: code,
|
|
207
|
+
};
|
|
208
|
+
if (scope !== undefined) {
|
|
209
|
+
tokenOptions.scope = scope;
|
|
210
|
+
}
|
|
211
|
+
await sdkAuth(provider, tokenOptions);
|
|
212
|
+
}
|
|
213
|
+
}
|
|
214
|
+
finally {
|
|
215
|
+
escapeHandler.cleanup();
|
|
216
|
+
}
|
|
217
|
+
const profile = provider._authProfile;
|
|
218
|
+
if (!profile) {
|
|
219
|
+
throw new ClientError('Failed to save authentication profile');
|
|
220
|
+
}
|
|
221
|
+
logger.debug('OAuth flow completed successfully');
|
|
222
|
+
return {
|
|
223
|
+
profile,
|
|
224
|
+
success: true,
|
|
225
|
+
};
|
|
226
|
+
}
|
|
227
|
+
catch (error) {
|
|
228
|
+
logger.error(`OAuth flow failed: ${error.message}`);
|
|
229
|
+
throw error;
|
|
230
|
+
}
|
|
231
|
+
finally {
|
|
232
|
+
destroyConnections();
|
|
233
|
+
server.close();
|
|
234
|
+
}
|
|
235
|
+
}
|
|
236
|
+
//# sourceMappingURL=oauth-flow.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"oauth-flow.js","sourceRoot":"","sources":["../../../src/lib/auth/oauth-flow.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import type { OAuthClientProvider } from '@modelcontextprotocol/sdk/client/auth.js';
|
|
2
|
+
import type { OAuthClientMetadata, OAuthClientInformationMixed, OAuthTokens } from '@modelcontextprotocol/sdk/shared/auth.js';
|
|
3
|
+
export declare class McpcOAuthProvider implements OAuthClientProvider {
|
|
4
|
+
private serverUrl;
|
|
5
|
+
private profileName;
|
|
6
|
+
private _redirectUrl;
|
|
7
|
+
private _authProfile;
|
|
8
|
+
private _codeVerifier;
|
|
9
|
+
private _clientInformation;
|
|
10
|
+
private _ignoreExistingTokens;
|
|
11
|
+
constructor(serverUrl: string, profileName: string, redirectUrl: string, ignoreExistingTokens?: boolean);
|
|
12
|
+
private loadProfile;
|
|
13
|
+
get redirectUrl(): string;
|
|
14
|
+
get clientMetadata(): OAuthClientMetadata;
|
|
15
|
+
clientInformation(): Promise<OAuthClientInformationMixed | undefined>;
|
|
16
|
+
saveClientInformation(clientInformation: OAuthClientInformationMixed): Promise<void>;
|
|
17
|
+
tokens(): Promise<OAuthTokens | undefined>;
|
|
18
|
+
saveTokens(tokens: OAuthTokens): Promise<void>;
|
|
19
|
+
redirectToAuthorization(authorizationUrl: URL): Promise<void>;
|
|
20
|
+
saveCodeVerifier(codeVerifier: string): Promise<void>;
|
|
21
|
+
codeVerifier(): Promise<string>;
|
|
22
|
+
setOAuthIssuer(issuer: string): void;
|
|
23
|
+
}
|
|
24
|
+
//# sourceMappingURL=oauth-provider.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"oauth-provider.d.ts","sourceRoot":"","sources":["../../../src/lib/auth/oauth-provider.ts"],"names":[],"mappings":"AAMA,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,0CAA0C,CAAC;AACpF,OAAO,KAAK,EACV,mBAAmB,EACnB,2BAA2B,EAC3B,WAAW,EACZ,MAAM,0CAA0C,CAAC;AAkBlD,qBAAa,iBAAkB,YAAW,mBAAmB;IAC3D,OAAO,CAAC,SAAS,CAAS;IAC1B,OAAO,CAAC,WAAW,CAAS;IAC5B,OAAO,CAAC,YAAY,CAAS;IAC7B,OAAO,CAAC,YAAY,CAA0B;IAC9C,OAAO,CAAC,aAAa,CAAqB;IAC1C,OAAO,CAAC,kBAAkB,CAA0C;IACpE,OAAO,CAAC,qBAAqB,CAAU;gBAE3B,SAAS,EAAE,MAAM,EAAE,WAAW,EAAE,MAAM,EAAE,WAAW,EAAE,MAAM,EAAE,oBAAoB,UAAQ;YAUvF,WAAW;IAOzB,IAAI,WAAW,IAAI,MAAM,CAExB;IAED,IAAI,cAAc,IAAI,mBAAmB,CASxC;IAEK,iBAAiB,IAAI,OAAO,CAAC,2BAA2B,GAAG,SAAS,CAAC;IAcrE,qBAAqB,CAAC,iBAAiB,EAAE,2BAA2B,GAAG,OAAO,CAAC,IAAI,CAAC;IAepF,MAAM,IAAI,OAAO,CAAC,WAAW,GAAG,SAAS,CAAC;IAgC1C,UAAU,CAAC,MAAM,EAAE,WAAW,GAAG,OAAO,CAAC,IAAI,CAAC;IAuD9C,uBAAuB,CAAC,gBAAgB,EAAE,GAAG,GAAG,OAAO,CAAC,IAAI,CAAC;IAM7D,gBAAgB,CAAC,YAAY,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAIrD,YAAY,IAAI,OAAO,CAAC,MAAM,CAAC;IAWrC,cAAc,CAAC,MAAM,EAAE,MAAM,GAAG,IAAI;CAKrC"}
|
|
@@ -0,0 +1,144 @@
|
|
|
1
|
+
import { getAuthProfile, saveAuthProfile } from '../auth/auth-profiles.js';
|
|
2
|
+
import { readKeychainOAuthTokenInfo, storeKeychainOAuthTokenInfo, readKeychainOAuthClientInfo, storeKeychainOAuthClientInfo, } from './keychain.js';
|
|
3
|
+
import { createLogger } from '../logger.js';
|
|
4
|
+
const logger = createLogger('oauth-provider');
|
|
5
|
+
export class McpcOAuthProvider {
|
|
6
|
+
serverUrl;
|
|
7
|
+
profileName;
|
|
8
|
+
_redirectUrl;
|
|
9
|
+
_authProfile;
|
|
10
|
+
_codeVerifier;
|
|
11
|
+
_clientInformation;
|
|
12
|
+
_ignoreExistingTokens;
|
|
13
|
+
constructor(serverUrl, profileName, redirectUrl, ignoreExistingTokens = false) {
|
|
14
|
+
this.serverUrl = serverUrl;
|
|
15
|
+
this.profileName = profileName;
|
|
16
|
+
this._redirectUrl = redirectUrl;
|
|
17
|
+
this._ignoreExistingTokens = ignoreExistingTokens;
|
|
18
|
+
}
|
|
19
|
+
async loadProfile() {
|
|
20
|
+
if (!this._authProfile) {
|
|
21
|
+
this._authProfile = await getAuthProfile(this.serverUrl, this.profileName);
|
|
22
|
+
}
|
|
23
|
+
return this._authProfile;
|
|
24
|
+
}
|
|
25
|
+
get redirectUrl() {
|
|
26
|
+
return this._redirectUrl;
|
|
27
|
+
}
|
|
28
|
+
get clientMetadata() {
|
|
29
|
+
return {
|
|
30
|
+
redirect_uris: [this._redirectUrl],
|
|
31
|
+
grant_types: ['authorization_code', 'refresh_token'],
|
|
32
|
+
response_types: ['code'],
|
|
33
|
+
token_endpoint_auth_method: 'none',
|
|
34
|
+
client_name: 'mcpc',
|
|
35
|
+
client_uri: 'https://github.com/apify/mcpc',
|
|
36
|
+
};
|
|
37
|
+
}
|
|
38
|
+
async clientInformation() {
|
|
39
|
+
if (!this._clientInformation) {
|
|
40
|
+
const storedClient = await readKeychainOAuthClientInfo(this.serverUrl, this.profileName);
|
|
41
|
+
if (storedClient) {
|
|
42
|
+
this._clientInformation = {
|
|
43
|
+
client_id: storedClient.clientId,
|
|
44
|
+
client_secret: storedClient.clientSecret,
|
|
45
|
+
};
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
return this._clientInformation;
|
|
49
|
+
}
|
|
50
|
+
async saveClientInformation(clientInformation) {
|
|
51
|
+
this._clientInformation = clientInformation;
|
|
52
|
+
const clientInfo = {
|
|
53
|
+
clientId: clientInformation.client_id,
|
|
54
|
+
};
|
|
55
|
+
if (clientInformation.client_secret) {
|
|
56
|
+
clientInfo.clientSecret = clientInformation.client_secret;
|
|
57
|
+
}
|
|
58
|
+
await storeKeychainOAuthClientInfo(this.serverUrl, this.profileName, clientInfo);
|
|
59
|
+
logger.debug('Saved client information to keychain');
|
|
60
|
+
}
|
|
61
|
+
async tokens() {
|
|
62
|
+
if (this._ignoreExistingTokens) {
|
|
63
|
+
return undefined;
|
|
64
|
+
}
|
|
65
|
+
const storedTokens = await readKeychainOAuthTokenInfo(this.serverUrl, this.profileName);
|
|
66
|
+
if (!storedTokens) {
|
|
67
|
+
return undefined;
|
|
68
|
+
}
|
|
69
|
+
const result = {
|
|
70
|
+
access_token: storedTokens.accessToken,
|
|
71
|
+
token_type: storedTokens.tokenType,
|
|
72
|
+
};
|
|
73
|
+
if (storedTokens.expiresIn !== undefined) {
|
|
74
|
+
result.expires_in = storedTokens.expiresIn;
|
|
75
|
+
}
|
|
76
|
+
if (storedTokens.refreshToken !== undefined) {
|
|
77
|
+
result.refresh_token = storedTokens.refreshToken;
|
|
78
|
+
}
|
|
79
|
+
if (storedTokens.scope !== undefined) {
|
|
80
|
+
result.scope = storedTokens.scope;
|
|
81
|
+
}
|
|
82
|
+
return result;
|
|
83
|
+
}
|
|
84
|
+
async saveTokens(tokens) {
|
|
85
|
+
logger.debug('Saving OAuth tokens to keychain');
|
|
86
|
+
const tokenInfo = {
|
|
87
|
+
accessToken: tokens.access_token,
|
|
88
|
+
tokenType: tokens.token_type,
|
|
89
|
+
};
|
|
90
|
+
if (tokens.expires_in !== undefined) {
|
|
91
|
+
tokenInfo.expiresIn = tokens.expires_in;
|
|
92
|
+
tokenInfo.expiresAt = Math.floor(Date.now() / 1000) + tokens.expires_in;
|
|
93
|
+
}
|
|
94
|
+
if (tokens.refresh_token !== undefined) {
|
|
95
|
+
tokenInfo.refreshToken = tokens.refresh_token;
|
|
96
|
+
}
|
|
97
|
+
if (tokens.scope !== undefined) {
|
|
98
|
+
tokenInfo.scope = tokens.scope;
|
|
99
|
+
}
|
|
100
|
+
await storeKeychainOAuthTokenInfo(this.serverUrl, this.profileName, tokenInfo);
|
|
101
|
+
const now = new Date().toISOString();
|
|
102
|
+
let profile = await this.loadProfile();
|
|
103
|
+
if (!profile) {
|
|
104
|
+
profile = {
|
|
105
|
+
name: this.profileName,
|
|
106
|
+
serverUrl: this.serverUrl,
|
|
107
|
+
authType: 'oauth',
|
|
108
|
+
oauthIssuer: '',
|
|
109
|
+
createdAt: now,
|
|
110
|
+
authenticatedAt: now,
|
|
111
|
+
};
|
|
112
|
+
if (tokens.scope) {
|
|
113
|
+
profile.scopes = tokens.scope.split(' ');
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
else {
|
|
117
|
+
profile.authenticatedAt = now;
|
|
118
|
+
if (tokens.scope) {
|
|
119
|
+
profile.scopes = tokens.scope.split(' ');
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
await saveAuthProfile(profile);
|
|
123
|
+
this._authProfile = profile;
|
|
124
|
+
logger.debug('Tokens saved to keychain, profile metadata updated');
|
|
125
|
+
}
|
|
126
|
+
async redirectToAuthorization(authorizationUrl) {
|
|
127
|
+
logger.info(`Authorization URL: ${authorizationUrl.toString()}`);
|
|
128
|
+
}
|
|
129
|
+
async saveCodeVerifier(codeVerifier) {
|
|
130
|
+
this._codeVerifier = codeVerifier;
|
|
131
|
+
}
|
|
132
|
+
async codeVerifier() {
|
|
133
|
+
if (!this._codeVerifier) {
|
|
134
|
+
throw new Error('Code verifier not found');
|
|
135
|
+
}
|
|
136
|
+
return this._codeVerifier;
|
|
137
|
+
}
|
|
138
|
+
setOAuthIssuer(issuer) {
|
|
139
|
+
if (this._authProfile) {
|
|
140
|
+
this._authProfile.oauthIssuer = issuer;
|
|
141
|
+
}
|
|
142
|
+
}
|
|
143
|
+
}
|
|
144
|
+
//# sourceMappingURL=oauth-provider.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"oauth-provider.js","sourceRoot":"","sources":["../../../src/lib/auth/oauth-provider.ts"],"names":[],"mappings":"AAaA,OAAO,EAAE,cAAc,EAAE,eAAe,EAAE,MAAM,0BAA0B,CAAC;AAC3E,OAAO,EACL,0BAA0B,EAC1B,2BAA2B,EAC3B,2BAA2B,EAC3B,4BAA4B,GAE7B,MAAM,eAAe,CAAC;AACvB,OAAO,EAAE,YAAY,EAAE,MAAM,cAAc,CAAC;AAE5C,MAAM,MAAM,GAAG,YAAY,CAAC,gBAAgB,CAAC,CAAC;AAM9C,MAAM,OAAO,iBAAiB;IACpB,SAAS,CAAS;IAClB,WAAW,CAAS;IACpB,YAAY,CAAS;IACrB,YAAY,CAA0B;IACtC,aAAa,CAAqB;IAClC,kBAAkB,CAA0C;IAC5D,qBAAqB,CAAU;IAEvC,YAAY,SAAiB,EAAE,WAAmB,EAAE,WAAmB,EAAE,oBAAoB,GAAG,KAAK;QACnG,IAAI,CAAC,SAAS,GAAG,SAAS,CAAC;QAC3B,IAAI,CAAC,WAAW,GAAG,WAAW,CAAC;QAC/B,IAAI,CAAC,YAAY,GAAG,WAAW,CAAC;QAChC,IAAI,CAAC,qBAAqB,GAAG,oBAAoB,CAAC;IACpD,CAAC;IAKO,KAAK,CAAC,WAAW;QACvB,IAAI,CAAC,IAAI,CAAC,YAAY,EAAE,CAAC;YACvB,IAAI,CAAC,YAAY,GAAG,MAAM,cAAc,CAAC,IAAI,CAAC,SAAS,EAAE,IAAI,CAAC,WAAW,CAAC,CAAC;QAC7E,CAAC;QACD,OAAO,IAAI,CAAC,YAAY,CAAC;IAC3B,CAAC;IAED,IAAI,WAAW;QACb,OAAO,IAAI,CAAC,YAAY,CAAC;IAC3B,CAAC;IAED,IAAI,cAAc;QAChB,OAAO;YACL,aAAa,EAAE,CAAC,IAAI,CAAC,YAAY,CAAC;YAClC,WAAW,EAAE,CAAC,oBAAoB,EAAE,eAAe,CAAC;YACpD,cAAc,EAAE,CAAC,MAAM,CAAC;YACxB,0BAA0B,EAAE,MAAM;YAClC,WAAW,EAAE,MAAM;YACnB,UAAU,EAAE,+BAA+B;SAC5C,CAAC;IACJ,CAAC;IAED,KAAK,CAAC,iBAAiB;QAErB,IAAI,CAAC,IAAI,CAAC,kBAAkB,EAAE,CAAC;YAC7B,MAAM,YAAY,GAAG,MAAM,2BAA2B,CAAC,IAAI,CAAC,SAAS,EAAE,IAAI,CAAC,WAAW,CAAC,CAAC;YACzF,IAAI,YAAY,EAAE,CAAC;gBACjB,IAAI,CAAC,kBAAkB,GAAG;oBACxB,SAAS,EAAE,YAAY,CAAC,QAAQ;oBAChC,aAAa,EAAE,YAAY,CAAC,YAAY;iBACzC,CAAC;YACJ,CAAC;QACH,CAAC;QACD,OAAO,IAAI,CAAC,kBAAkB,CAAC;IACjC,CAAC;IAED,KAAK,CAAC,qBAAqB,CAAC,iBAA8C;QACxE,IAAI,CAAC,kBAAkB,GAAG,iBAAiB,CAAC;QAG5C,MAAM,UAAU,GAAuD;YACrE,QAAQ,EAAE,iBAAiB,CAAC,SAAS;SACtC,CAAC;QACF,IAAI,iBAAiB,CAAC,aAAa,EAAE,CAAC;YACpC,UAAU,CAAC,YAAY,GAAG,iBAAiB,CAAC,aAAa,CAAC;QAC5D,CAAC;QACD,MAAM,4BAA4B,CAAC,IAAI,CAAC,SAAS,EAAE,IAAI,CAAC,WAAW,EAAE,UAAU,CAAC,CAAC;QAEjF,MAAM,CAAC,KAAK,CAAC,sCAAsC,CAAC,CAAC;IACvD,CAAC;IAED,KAAK,CAAC,MAAM;QAGV,IAAI,IAAI,CAAC,qBAAqB,EAAE,CAAC;YAC/B,OAAO,SAAS,CAAC;QACnB,CAAC;QAGD,MAAM,YAAY,GAAG,MAAM,0BAA0B,CAAC,IAAI,CAAC,SAAS,EAAE,IAAI,CAAC,WAAW,CAAC,CAAC;QACxF,IAAI,CAAC,YAAY,EAAE,CAAC;YAClB,OAAO,SAAS,CAAC;QACnB,CAAC;QAGD,MAAM,MAAM,GAAgB;YAC1B,YAAY,EAAE,YAAY,CAAC,WAAW;YACtC,UAAU,EAAE,YAAY,CAAC,SAAS;SACnC,CAAC;QAEF,IAAI,YAAY,CAAC,SAAS,KAAK,SAAS,EAAE,CAAC;YACzC,MAAM,CAAC,UAAU,GAAG,YAAY,CAAC,SAAS,CAAC;QAC7C,CAAC;QACD,IAAI,YAAY,CAAC,YAAY,KAAK,SAAS,EAAE,CAAC;YAC5C,MAAM,CAAC,aAAa,GAAG,YAAY,CAAC,YAAY,CAAC;QACnD,CAAC;QACD,IAAI,YAAY,CAAC,KAAK,KAAK,SAAS,EAAE,CAAC;YACrC,MAAM,CAAC,KAAK,GAAG,YAAY,CAAC,KAAK,CAAC;QACpC,CAAC;QAED,OAAO,MAAM,CAAC;IAChB,CAAC;IAED,KAAK,CAAC,UAAU,CAAC,MAAmB;QAClC,MAAM,CAAC,KAAK,CAAC,iCAAiC,CAAC,CAAC;QAGhD,MAAM,SAAS,GAAmB;YAChC,WAAW,EAAE,MAAM,CAAC,YAAY;YAChC,SAAS,EAAE,MAAM,CAAC,UAAU;SAC7B,CAAC;QAEF,IAAI,MAAM,CAAC,UAAU,KAAK,SAAS,EAAE,CAAC;YACpC,SAAS,CAAC,SAAS,GAAG,MAAM,CAAC,UAAU,CAAC;YACxC,SAAS,CAAC,SAAS,GAAG,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,GAAG,EAAE,GAAG,IAAI,CAAC,GAAG,MAAM,CAAC,UAAU,CAAC;QAC1E,CAAC;QACD,IAAI,MAAM,CAAC,aAAa,KAAK,SAAS,EAAE,CAAC;YACvC,SAAS,CAAC,YAAY,GAAG,MAAM,CAAC,aAAa,CAAC;QAChD,CAAC;QACD,IAAI,MAAM,CAAC,KAAK,KAAK,SAAS,EAAE,CAAC;YAC/B,SAAS,CAAC,KAAK,GAAG,MAAM,CAAC,KAAK,CAAC;QACjC,CAAC;QAED,MAAM,2BAA2B,CAAC,IAAI,CAAC,SAAS,EAAE,IAAI,CAAC,WAAW,EAAE,SAAS,CAAC,CAAC;QAG/E,MAAM,GAAG,GAAG,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE,CAAC;QACrC,IAAI,OAAO,GAAG,MAAM,IAAI,CAAC,WAAW,EAAE,CAAC;QAEvC,IAAI,CAAC,OAAO,EAAE,CAAC;YAEb,OAAO,GAAG;gBACR,IAAI,EAAE,IAAI,CAAC,WAAW;gBACtB,SAAS,EAAE,IAAI,CAAC,SAAS;gBACzB,QAAQ,EAAE,OAAO;gBACjB,WAAW,EAAE,EAAE;gBACf,SAAS,EAAE,GAAG;gBACd,eAAe,EAAE,GAAG;aACrB,CAAC;YAEF,IAAI,MAAM,CAAC,KAAK,EAAE,CAAC;gBACjB,OAAO,CAAC,MAAM,GAAG,MAAM,CAAC,KAAK,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC;YAC3C,CAAC;QACH,CAAC;aAAM,CAAC;YAEN,OAAO,CAAC,eAAe,GAAG,GAAG,CAAC;YAE9B,IAAI,MAAM,CAAC,KAAK,EAAE,CAAC;gBACjB,OAAO,CAAC,MAAM,GAAG,MAAM,CAAC,KAAK,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC;YAC3C,CAAC;QACH,CAAC;QAED,MAAM,eAAe,CAAC,OAAO,CAAC,CAAC;QAC/B,IAAI,CAAC,YAAY,GAAG,OAAO,CAAC;QAE5B,MAAM,CAAC,KAAK,CAAC,oDAAoD,CAAC,CAAC;IACrE,CAAC;IAED,KAAK,CAAC,uBAAuB,CAAC,gBAAqB;QAGjD,MAAM,CAAC,IAAI,CAAC,sBAAsB,gBAAgB,CAAC,QAAQ,EAAE,EAAE,CAAC,CAAC;IACnE,CAAC;IAED,KAAK,CAAC,gBAAgB,CAAC,YAAoB;QACzC,IAAI,CAAC,aAAa,GAAG,YAAY,CAAC;IACpC,CAAC;IAED,KAAK,CAAC,YAAY;QAChB,IAAI,CAAC,IAAI,CAAC,aAAa,EAAE,CAAC;YACxB,MAAM,IAAI,KAAK,CAAC,yBAAyB,CAAC,CAAC;QAC7C,CAAC;QACD,OAAO,IAAI,CAAC,aAAa,CAAC;IAC5B,CAAC;IAMD,cAAc,CAAC,MAAc;QAC3B,IAAI,IAAI,CAAC,YAAY,EAAE,CAAC;YACtB,IAAI,CAAC,YAAY,CAAC,WAAW,GAAG,MAAM,CAAC;QACzC,CAAC;IACH,CAAC;CACF"}
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import { type OAuthTokenResponse } from './oauth-utils.js';
|
|
2
|
+
export type OnTokenRefreshCallback = (tokens: OAuthTokenResponse) => void | Promise<void>;
|
|
3
|
+
export interface OAuthTokenManagerOptions {
|
|
4
|
+
serverUrl: string;
|
|
5
|
+
profileName: string;
|
|
6
|
+
clientId: string;
|
|
7
|
+
refreshToken: string;
|
|
8
|
+
accessToken?: string;
|
|
9
|
+
accessTokenExpiresAt?: number;
|
|
10
|
+
onTokenRefresh?: OnTokenRefreshCallback;
|
|
11
|
+
}
|
|
12
|
+
export declare class OAuthTokenManager {
|
|
13
|
+
private serverUrl;
|
|
14
|
+
private profileName;
|
|
15
|
+
private clientId;
|
|
16
|
+
private refreshToken;
|
|
17
|
+
private accessToken;
|
|
18
|
+
private accessTokenExpiresAt;
|
|
19
|
+
private onTokenRefresh?;
|
|
20
|
+
constructor(options: OAuthTokenManagerOptions);
|
|
21
|
+
isAccessTokenExpired(): boolean;
|
|
22
|
+
refreshAccessToken(): Promise<OAuthTokenResponse>;
|
|
23
|
+
getValidAccessToken(): Promise<string>;
|
|
24
|
+
}
|
|
25
|
+
//# sourceMappingURL=oauth-token-manager.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"oauth-token-manager.d.ts","sourceRoot":"","sources":["../../../src/lib/auth/oauth-token-manager.ts"],"names":[],"mappings":"AAQA,OAAO,EAA8C,KAAK,kBAAkB,EAAE,MAAM,kBAAkB,CAAC;AAcvG,MAAM,MAAM,sBAAsB,GAAG,CAAC,MAAM,EAAE,kBAAkB,KAAK,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;AAK1F,MAAM,WAAW,wBAAwB;IACvC,SAAS,EAAE,MAAM,CAAC;IAClB,WAAW,EAAE,MAAM,CAAC;IAEpB,QAAQ,EAAE,MAAM,CAAC;IAEjB,YAAY,EAAE,MAAM,CAAC;IAErB,WAAW,CAAC,EAAE,MAAM,CAAC;IAErB,oBAAoB,CAAC,EAAE,MAAM,CAAC;IAE9B,cAAc,CAAC,EAAE,sBAAsB,CAAC;CACzC;AAKD,qBAAa,iBAAiB;IAC5B,OAAO,CAAC,SAAS,CAAS;IAC1B,OAAO,CAAC,WAAW,CAAS;IAC5B,OAAO,CAAC,QAAQ,CAAS;IACzB,OAAO,CAAC,YAAY,CAAS;IAC7B,OAAO,CAAC,WAAW,CAAuB;IAC1C,OAAO,CAAC,oBAAoB,CAAuB;IACnD,OAAO,CAAC,cAAc,CAAC,CAAyB;gBAEpC,OAAO,EAAE,wBAAwB;IAe7C,oBAAoB,IAAI,OAAO;IAYzB,kBAAkB,IAAI,OAAO,CAAC,kBAAkB,CAAC;IAsDjD,mBAAmB,IAAI,OAAO,CAAC,MAAM,CAAC;CAW7C"}
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
import { createLogger } from '../logger.js';
|
|
2
|
+
import { AuthError } from '../errors.js';
|
|
3
|
+
import { discoverAndRefreshToken, createReauthError } from './oauth-utils.js';
|
|
4
|
+
const logger = createLogger('oauth-token-manager');
|
|
5
|
+
const DEFAULT_TOKEN_EXPIRY_SECONDS = 3600;
|
|
6
|
+
const EXPIRY_BUFFER_SECONDS = 60;
|
|
7
|
+
export class OAuthTokenManager {
|
|
8
|
+
serverUrl;
|
|
9
|
+
profileName;
|
|
10
|
+
clientId;
|
|
11
|
+
refreshToken;
|
|
12
|
+
accessToken = null;
|
|
13
|
+
accessTokenExpiresAt = null;
|
|
14
|
+
onTokenRefresh;
|
|
15
|
+
constructor(options) {
|
|
16
|
+
this.serverUrl = options.serverUrl;
|
|
17
|
+
this.profileName = options.profileName;
|
|
18
|
+
this.clientId = options.clientId;
|
|
19
|
+
this.refreshToken = options.refreshToken;
|
|
20
|
+
this.accessToken = options.accessToken ?? null;
|
|
21
|
+
this.accessTokenExpiresAt = options.accessTokenExpiresAt ?? null;
|
|
22
|
+
if (options.onTokenRefresh) {
|
|
23
|
+
this.onTokenRefresh = options.onTokenRefresh;
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
isAccessTokenExpired() {
|
|
27
|
+
if (!this.accessToken || !this.accessTokenExpiresAt) {
|
|
28
|
+
return true;
|
|
29
|
+
}
|
|
30
|
+
return Date.now() / 1000 > this.accessTokenExpiresAt - EXPIRY_BUFFER_SECONDS;
|
|
31
|
+
}
|
|
32
|
+
async refreshAccessToken() {
|
|
33
|
+
if (!this.refreshToken) {
|
|
34
|
+
throw createReauthError(this.serverUrl, this.profileName, `No refresh token available for profile ${this.profileName}`);
|
|
35
|
+
}
|
|
36
|
+
logger.debug(`Refreshing access token for profile: ${this.profileName}`);
|
|
37
|
+
try {
|
|
38
|
+
const tokenResponse = await discoverAndRefreshToken(this.serverUrl, this.refreshToken, this.clientId);
|
|
39
|
+
this.accessToken = tokenResponse.access_token;
|
|
40
|
+
const expiresIn = tokenResponse.expires_in ?? DEFAULT_TOKEN_EXPIRY_SECONDS;
|
|
41
|
+
this.accessTokenExpiresAt = Math.floor(Date.now() / 1000) + expiresIn;
|
|
42
|
+
if (tokenResponse.refresh_token) {
|
|
43
|
+
this.refreshToken = tokenResponse.refresh_token;
|
|
44
|
+
logger.debug('Received new refresh token (token rotation)');
|
|
45
|
+
}
|
|
46
|
+
logger.debug(`Access token refreshed successfully for profile: ${this.profileName}`);
|
|
47
|
+
if (this.onTokenRefresh) {
|
|
48
|
+
await this.onTokenRefresh(tokenResponse);
|
|
49
|
+
}
|
|
50
|
+
return tokenResponse;
|
|
51
|
+
}
|
|
52
|
+
catch (error) {
|
|
53
|
+
if (error instanceof AuthError) {
|
|
54
|
+
throw createReauthError(this.serverUrl, this.profileName, error.message);
|
|
55
|
+
}
|
|
56
|
+
logger.error(`Token refresh error: ${error.message}`);
|
|
57
|
+
throw createReauthError(this.serverUrl, this.profileName, `Failed to refresh token: ${error.message}`);
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
async getValidAccessToken() {
|
|
61
|
+
if (this.isAccessTokenExpired()) {
|
|
62
|
+
await this.refreshAccessToken();
|
|
63
|
+
}
|
|
64
|
+
if (!this.accessToken) {
|
|
65
|
+
throw new AuthError('No access token available after refresh');
|
|
66
|
+
}
|
|
67
|
+
return this.accessToken;
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
//# sourceMappingURL=oauth-token-manager.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"oauth-token-manager.js","sourceRoot":"","sources":["../../../src/lib/auth/oauth-token-manager.ts"],"names":[],"mappings":"AAMA,OAAO,EAAE,YAAY,EAAE,MAAM,cAAc,CAAC;AAC5C,OAAO,EAAE,SAAS,EAAE,MAAM,cAAc,CAAC;AACzC,OAAO,EAAE,uBAAuB,EAAE,iBAAiB,EAA2B,MAAM,kBAAkB,CAAC;AAEvG,MAAM,MAAM,GAAG,YAAY,CAAC,qBAAqB,CAAC,CAAC;AAGnD,MAAM,4BAA4B,GAAG,IAAI,CAAC;AAG1C,MAAM,qBAAqB,GAAG,EAAE,CAAC;AA6BjC,MAAM,OAAO,iBAAiB;IACpB,SAAS,CAAS;IAClB,WAAW,CAAS;IACpB,QAAQ,CAAS;IACjB,YAAY,CAAS;IACrB,WAAW,GAAkB,IAAI,CAAC;IAClC,oBAAoB,GAAkB,IAAI,CAAC;IAC3C,cAAc,CAA0B;IAEhD,YAAY,OAAiC;QAC3C,IAAI,CAAC,SAAS,GAAG,OAAO,CAAC,SAAS,CAAC;QACnC,IAAI,CAAC,WAAW,GAAG,OAAO,CAAC,WAAW,CAAC;QACvC,IAAI,CAAC,QAAQ,GAAG,OAAO,CAAC,QAAQ,CAAC;QACjC,IAAI,CAAC,YAAY,GAAG,OAAO,CAAC,YAAY,CAAC;QACzC,IAAI,CAAC,WAAW,GAAG,OAAO,CAAC,WAAW,IAAI,IAAI,CAAC;QAC/C,IAAI,CAAC,oBAAoB,GAAG,OAAO,CAAC,oBAAoB,IAAI,IAAI,CAAC;QACjE,IAAI,OAAO,CAAC,cAAc,EAAE,CAAC;YAC3B,IAAI,CAAC,cAAc,GAAG,OAAO,CAAC,cAAc,CAAC;QAC/C,CAAC;IACH,CAAC;IAKD,oBAAoB;QAClB,IAAI,CAAC,IAAI,CAAC,WAAW,IAAI,CAAC,IAAI,CAAC,oBAAoB,EAAE,CAAC;YACpD,OAAO,IAAI,CAAC;QACd,CAAC;QACD,OAAO,IAAI,CAAC,GAAG,EAAE,GAAG,IAAI,GAAG,IAAI,CAAC,oBAAoB,GAAG,qBAAqB,CAAC;IAC/E,CAAC;IAOD,KAAK,CAAC,kBAAkB;QACtB,IAAI,CAAC,IAAI,CAAC,YAAY,EAAE,CAAC;YACvB,MAAM,iBAAiB,CACrB,IAAI,CAAC,SAAS,EACd,IAAI,CAAC,WAAW,EAChB,0CAA0C,IAAI,CAAC,WAAW,EAAE,CAC7D,CAAC;QACJ,CAAC;QAED,MAAM,CAAC,KAAK,CAAC,wCAAwC,IAAI,CAAC,WAAW,EAAE,CAAC,CAAC;QAEzE,IAAI,CAAC;YACH,MAAM,aAAa,GAAG,MAAM,uBAAuB,CAAC,IAAI,CAAC,SAAS,EAAE,IAAI,CAAC,YAAY,EAAE,IAAI,CAAC,QAAQ,CAAC,CAAC;YAGtG,IAAI,CAAC,WAAW,GAAG,aAAa,CAAC,YAAY,CAAC;YAG9C,MAAM,SAAS,GAAG,aAAa,CAAC,UAAU,IAAI,4BAA4B,CAAC;YAC3E,IAAI,CAAC,oBAAoB,GAAG,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,GAAG,EAAE,GAAG,IAAI,CAAC,GAAG,SAAS,CAAC;YAGtE,IAAI,aAAa,CAAC,aAAa,EAAE,CAAC;gBAChC,IAAI,CAAC,YAAY,GAAG,aAAa,CAAC,aAAa,CAAC;gBAChD,MAAM,CAAC,KAAK,CAAC,6CAA6C,CAAC,CAAC;YAC9D,CAAC;YAED,MAAM,CAAC,KAAK,CAAC,oDAAoD,IAAI,CAAC,WAAW,EAAE,CAAC,CAAC;YAGrF,IAAI,IAAI,CAAC,cAAc,EAAE,CAAC;gBACxB,MAAM,IAAI,CAAC,cAAc,CAAC,aAAa,CAAC,CAAC;YAC3C,CAAC;YAED,OAAO,aAAa,CAAC;QACvB,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACf,IAAI,KAAK,YAAY,SAAS,EAAE,CAAC;gBAE/B,MAAM,iBAAiB,CAAC,IAAI,CAAC,SAAS,EAAE,IAAI,CAAC,WAAW,EAAE,KAAK,CAAC,OAAO,CAAC,CAAC;YAC3E,CAAC;YACD,MAAM,CAAC,KAAK,CAAC,wBAAyB,KAAe,CAAC,OAAO,EAAE,CAAC,CAAC;YACjE,MAAM,iBAAiB,CACrB,IAAI,CAAC,SAAS,EACd,IAAI,CAAC,WAAW,EAChB,4BAA6B,KAAe,CAAC,OAAO,EAAE,CACvD,CAAC;QACJ,CAAC;IACH,CAAC;IAOD,KAAK,CAAC,mBAAmB;QACvB,IAAI,IAAI,CAAC,oBAAoB,EAAE,EAAE,CAAC;YAChC,MAAM,IAAI,CAAC,kBAAkB,EAAE,CAAC;QAClC,CAAC;QAED,IAAI,CAAC,IAAI,CAAC,WAAW,EAAE,CAAC;YACtB,MAAM,IAAI,SAAS,CAAC,yCAAyC,CAAC,CAAC;QACjE,CAAC;QAED,OAAO,IAAI,CAAC,WAAW,CAAC;IAC1B,CAAC;CACF"}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import { AuthError } from '../errors.js';
|
|
2
|
+
export declare const DEFAULT_AUTH_PROFILE = "default";
|
|
3
|
+
export interface OAuthTokenResponse {
|
|
4
|
+
access_token: string;
|
|
5
|
+
token_type: string;
|
|
6
|
+
expires_in?: number;
|
|
7
|
+
refresh_token?: string;
|
|
8
|
+
scope?: string;
|
|
9
|
+
}
|
|
10
|
+
export declare function discoverTokenEndpoint(serverUrl: string): Promise<string | undefined>;
|
|
11
|
+
export declare function refreshAccessToken(tokenEndpoint: string, refreshToken: string, clientId: string): Promise<OAuthTokenResponse>;
|
|
12
|
+
export declare function discoverAndRefreshToken(serverUrl: string, refreshToken: string, clientId: string): Promise<OAuthTokenResponse>;
|
|
13
|
+
export declare function createReauthError(serverUrl: string, profileName: string, message: string): AuthError;
|
|
14
|
+
//# sourceMappingURL=oauth-utils.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"oauth-utils.d.ts","sourceRoot":"","sources":["../../../src/lib/auth/oauth-utils.ts"],"names":[],"mappings":"AAMA,OAAO,EAAE,SAAS,EAAE,MAAM,cAAc,CAAC;AAIzC,eAAO,MAAM,oBAAoB,YAAY,CAAC;AAK9C,MAAM,WAAW,kBAAkB;IACjC,YAAY,EAAE,MAAM,CAAC;IACrB,UAAU,EAAE,MAAM,CAAC;IACnB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB;AAMD,wBAAsB,qBAAqB,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,GAAG,SAAS,CAAC,CA0B1F;AAYD,wBAAsB,kBAAkB,CACtC,aAAa,EAAE,MAAM,EACrB,YAAY,EAAE,MAAM,EACpB,QAAQ,EAAE,MAAM,GACf,OAAO,CAAC,kBAAkB,CAAC,CAiC7B;AAYD,wBAAsB,uBAAuB,CAC3C,SAAS,EAAE,MAAM,EACjB,YAAY,EAAE,MAAM,EACpB,QAAQ,EAAE,MAAM,GACf,OAAO,CAAC,kBAAkB,CAAC,CAO7B;AAOD,wBAAgB,iBAAiB,CAC/B,SAAS,EAAE,MAAM,EACjB,WAAW,EAAE,MAAM,EACnB,OAAO,EAAE,MAAM,GACd,SAAS,CAMX"}
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
import { createLogger } from '../logger.js';
|
|
2
|
+
import { AuthError } from '../errors.js';
|
|
3
|
+
const logger = createLogger('oauth-utils');
|
|
4
|
+
export const DEFAULT_AUTH_PROFILE = 'default';
|
|
5
|
+
export async function discoverTokenEndpoint(serverUrl) {
|
|
6
|
+
const discoveryUrls = [
|
|
7
|
+
`${serverUrl}/.well-known/oauth-authorization-server`,
|
|
8
|
+
`${serverUrl}/.well-known/openid-configuration`,
|
|
9
|
+
];
|
|
10
|
+
for (const url of discoveryUrls) {
|
|
11
|
+
try {
|
|
12
|
+
logger.debug(`Trying OAuth discovery at: ${url}`);
|
|
13
|
+
const response = await fetch(url, {
|
|
14
|
+
headers: { Accept: 'application/json' },
|
|
15
|
+
});
|
|
16
|
+
if (response.ok) {
|
|
17
|
+
const metadata = await response.json();
|
|
18
|
+
if (metadata.token_endpoint) {
|
|
19
|
+
logger.debug(`Found token endpoint: ${metadata.token_endpoint}`);
|
|
20
|
+
return metadata.token_endpoint;
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
catch {
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
return undefined;
|
|
28
|
+
}
|
|
29
|
+
export async function refreshAccessToken(tokenEndpoint, refreshToken, clientId) {
|
|
30
|
+
logger.debug(`Refreshing token at: ${tokenEndpoint}`);
|
|
31
|
+
const params = new URLSearchParams({
|
|
32
|
+
grant_type: 'refresh_token',
|
|
33
|
+
refresh_token: refreshToken,
|
|
34
|
+
client_id: clientId,
|
|
35
|
+
});
|
|
36
|
+
const response = await fetch(tokenEndpoint, {
|
|
37
|
+
method: 'POST',
|
|
38
|
+
headers: {
|
|
39
|
+
'Content-Type': 'application/x-www-form-urlencoded',
|
|
40
|
+
Accept: 'application/json',
|
|
41
|
+
},
|
|
42
|
+
body: params.toString(),
|
|
43
|
+
});
|
|
44
|
+
if (!response.ok) {
|
|
45
|
+
const errorText = await response.text();
|
|
46
|
+
logger.error(`Token refresh failed: ${response.status} ${errorText}`);
|
|
47
|
+
if (response.status === 400 || response.status === 401) {
|
|
48
|
+
throw new AuthError('Refresh token is invalid or expired');
|
|
49
|
+
}
|
|
50
|
+
throw new AuthError(`Failed to refresh token: ${response.status} ${response.statusText}`);
|
|
51
|
+
}
|
|
52
|
+
const tokenResponse = await response.json();
|
|
53
|
+
return tokenResponse;
|
|
54
|
+
}
|
|
55
|
+
export async function discoverAndRefreshToken(serverUrl, refreshToken, clientId) {
|
|
56
|
+
const tokenEndpoint = await discoverTokenEndpoint(serverUrl);
|
|
57
|
+
if (!tokenEndpoint) {
|
|
58
|
+
throw new AuthError(`Could not find OAuth token endpoint for ${serverUrl}`);
|
|
59
|
+
}
|
|
60
|
+
return refreshAccessToken(tokenEndpoint, refreshToken, clientId);
|
|
61
|
+
}
|
|
62
|
+
export function createReauthError(serverUrl, profileName, message) {
|
|
63
|
+
const command = profileName === DEFAULT_AUTH_PROFILE
|
|
64
|
+
? `mcpc ${serverUrl} login`
|
|
65
|
+
: `mcpc ${serverUrl} login --profile ${profileName}`;
|
|
66
|
+
return new AuthError(`${message}. Please re-authenticate with: ${command}`);
|
|
67
|
+
}
|
|
68
|
+
//# sourceMappingURL=oauth-utils.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"oauth-utils.js","sourceRoot":"","sources":["../../../src/lib/auth/oauth-utils.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"token-refresh.d.ts","sourceRoot":"","sources":["../../../src/lib/auth/token-refresh.ts"],"names":[],"mappings":"AAmEA,wBAAsB,+BAA+B,CACnD,SAAS,EAAE,MAAM,EACjB,WAAW,GAAE,MAA6B,GACzC,OAAO,CAAC,MAAM,GAAG,SAAS,CAAC,CAqD7B"}
|