mcp4openapi 0.1.0 → 0.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 +134 -95
- package/dist/scripts/validate-profile.js +3 -3
- package/dist/scripts/validate-profile.js.map +1 -1
- package/dist/src/composite-executor.d.ts +3 -1
- package/dist/src/composite-executor.d.ts.map +1 -1
- package/dist/src/composite-executor.js +16 -5
- package/dist/src/composite-executor.js.map +1 -1
- package/dist/src/constants.d.ts +49 -0
- package/dist/src/constants.d.ts.map +1 -1
- package/dist/src/constants.js +49 -0
- package/dist/src/constants.js.map +1 -1
- package/dist/src/errors.d.ts +6 -0
- package/dist/src/errors.d.ts.map +1 -1
- package/dist/src/errors.js +13 -0
- package/dist/src/errors.js.map +1 -1
- package/dist/src/generated-schemas.d.ts +832 -52
- package/dist/src/generated-schemas.d.ts.map +1 -1
- package/dist/src/generated-schemas.js +31 -8
- package/dist/src/generated-schemas.js.map +1 -1
- package/dist/src/http-client-factory.d.ts.map +1 -1
- package/dist/src/http-client-factory.js +14 -3
- package/dist/src/http-client-factory.js.map +1 -1
- package/dist/src/http-transport.d.ts +65 -0
- package/dist/src/http-transport.d.ts.map +1 -1
- package/dist/src/http-transport.js +921 -77
- package/dist/src/http-transport.js.map +1 -1
- package/dist/src/index.js +108 -8
- package/dist/src/index.js.map +1 -1
- package/dist/src/interceptors.d.ts +3 -0
- package/dist/src/interceptors.d.ts.map +1 -1
- package/dist/src/interceptors.js +50 -8
- package/dist/src/interceptors.js.map +1 -1
- package/dist/src/logger.d.ts +1 -1
- package/dist/src/logger.js +3 -3
- package/dist/src/logger.js.map +1 -1
- package/dist/src/mcp-server.d.ts +33 -0
- package/dist/src/mcp-server.d.ts.map +1 -1
- package/dist/src/mcp-server.js +263 -54
- package/dist/src/mcp-server.js.map +1 -1
- package/dist/src/oauth-provider.d.ts +92 -0
- package/dist/src/oauth-provider.d.ts.map +1 -0
- package/dist/src/oauth-provider.js +588 -0
- package/dist/src/oauth-provider.js.map +1 -0
- package/dist/src/openapi-parser.d.ts +16 -0
- package/dist/src/openapi-parser.d.ts.map +1 -1
- package/dist/src/openapi-parser.js +141 -6
- package/dist/src/openapi-parser.js.map +1 -1
- package/dist/src/profile-loader.d.ts +2 -2
- package/dist/src/profile-loader.d.ts.map +1 -1
- package/dist/src/profile-loader.js +45 -24
- package/dist/src/profile-loader.js.map +1 -1
- package/dist/src/testing/fixtures.d.ts +32 -0
- package/dist/src/testing/fixtures.d.ts.map +1 -1
- package/dist/src/testing/fixtures.js +26 -0
- package/dist/src/testing/fixtures.js.map +1 -1
- package/dist/src/testing/mock-gitlab-server.d.ts.map +1 -1
- package/dist/src/testing/mock-gitlab-server.js +131 -1
- package/dist/src/testing/mock-gitlab-server.js.map +1 -1
- package/dist/src/types/http-transport.d.ts +16 -0
- package/dist/src/types/http-transport.d.ts.map +1 -1
- package/dist/src/types/openapi.d.ts +5 -0
- package/dist/src/types/openapi.d.ts.map +1 -1
- package/dist/src/types/profile.d.ts +112 -3
- package/dist/src/types/profile.d.ts.map +1 -1
- package/dist/src/validation-utils.d.ts +12 -0
- package/dist/src/validation-utils.d.ts.map +1 -1
- package/dist/src/validation-utils.js +17 -0
- package/dist/src/validation-utils.js.map +1 -1
- package/package.json +7 -3
- package/profile-schema.json +169 -7
- package/dist/composite-executor.d.ts +0 -65
- package/dist/composite-executor.d.ts.map +0 -1
- package/dist/composite-executor.js +0 -147
- package/dist/composite-executor.js.map +0 -1
- package/dist/constants.d.ts +0 -36
- package/dist/constants.d.ts.map +0 -1
- package/dist/constants.js +0 -36
- package/dist/constants.js.map +0 -1
- package/dist/http-transport.d.ts +0 -195
- package/dist/http-transport.d.ts.map +0 -1
- package/dist/http-transport.js +0 -760
- package/dist/http-transport.js.map +0 -1
- package/dist/interceptors.d.ts +0 -74
- package/dist/interceptors.d.ts.map +0 -1
- package/dist/interceptors.js +0 -220
- package/dist/interceptors.js.map +0 -1
- package/dist/logger.d.ts +0 -81
- package/dist/logger.d.ts.map +0 -1
- package/dist/logger.js +0 -264
- package/dist/logger.js.map +0 -1
- package/dist/mcp-server.d.ts +0 -110
- package/dist/mcp-server.d.ts.map +0 -1
- package/dist/mcp-server.js +0 -568
- package/dist/mcp-server.js.map +0 -1
- package/dist/metrics.d.ts +0 -86
- package/dist/metrics.d.ts.map +0 -1
- package/dist/metrics.js +0 -229
- package/dist/metrics.js.map +0 -1
- package/dist/openapi-parser.d.ts +0 -35
- package/dist/openapi-parser.d.ts.map +0 -1
- package/dist/openapi-parser.js +0 -160
- package/dist/openapi-parser.js.map +0 -1
- package/dist/profile-loader.d.ts +0 -25
- package/dist/profile-loader.d.ts.map +0 -1
- package/dist/profile-loader.js +0 -134
- package/dist/profile-loader.js.map +0 -1
- package/dist/schema-validator.d.ts +0 -32
- package/dist/schema-validator.d.ts.map +0 -1
- package/dist/schema-validator.js +0 -126
- package/dist/schema-validator.js.map +0 -1
- package/dist/testing/fixtures.d.ts +0 -186
- package/dist/testing/fixtures.d.ts.map +0 -1
- package/dist/testing/fixtures.js +0 -135
- package/dist/testing/fixtures.js.map +0 -1
- package/dist/testing/http-integration.test.d.ts +0 -7
- package/dist/testing/http-integration.test.d.ts.map +0 -1
- package/dist/testing/http-integration.test.js +0 -383
- package/dist/testing/http-integration.test.js.map +0 -1
- package/dist/testing/http-multiuser.test.d.ts +0 -10
- package/dist/testing/http-multiuser.test.d.ts.map +0 -1
- package/dist/testing/http-multiuser.test.js +0 -255
- package/dist/testing/http-multiuser.test.js.map +0 -1
- package/dist/testing/integration.test.d.ts +0 -8
- package/dist/testing/integration.test.d.ts.map +0 -1
- package/dist/testing/integration.test.js +0 -247
- package/dist/testing/integration.test.js.map +0 -1
- package/dist/testing/mock-gitlab-server.d.ts +0 -34
- package/dist/testing/mock-gitlab-server.d.ts.map +0 -1
- package/dist/testing/mock-gitlab-server.js +0 -224
- package/dist/testing/mock-gitlab-server.js.map +0 -1
- package/dist/testing/test-types.d.ts +0 -59
- package/dist/testing/test-types.d.ts.map +0 -1
- package/dist/testing/test-types.js +0 -7
- package/dist/testing/test-types.js.map +0 -1
- package/dist/tool-generator.d.ts +0 -43
- package/dist/tool-generator.d.ts.map +0 -1
- package/dist/tool-generator.js +0 -123
- package/dist/tool-generator.js.map +0 -1
- package/dist/tsconfig.tsbuildinfo +0 -1
- package/dist/types/http-transport.d.ts +0 -39
- package/dist/types/http-transport.d.ts.map +0 -1
- package/dist/types/http-transport.js +0 -8
- package/dist/types/http-transport.js.map +0 -1
- package/dist/types/openapi.d.ts +0 -50
- package/dist/types/openapi.d.ts.map +0 -1
- package/dist/types/openapi.js +0 -9
- package/dist/types/openapi.js.map +0 -1
- package/dist/types/profile.d.ts +0 -76
- package/dist/types/profile.d.ts.map +0 -1
- package/dist/types/profile.js +0 -9
- package/dist/types/profile.js.map +0 -1
|
@@ -0,0 +1,588 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* OAuth 2.0 Provider Adapter
|
|
3
|
+
*
|
|
4
|
+
* Implements MCP SDK OAuthServerProvider interface to integrate with external
|
|
5
|
+
* OAuth 2.0 authorization servers (e.g., GitLab, GitHub, etc.)
|
|
6
|
+
*
|
|
7
|
+
* Architecture:
|
|
8
|
+
* - This server acts as an OAuth client to the external provider (Proxy/Gateway)
|
|
9
|
+
* - Implements "Callback Mode":
|
|
10
|
+
* 1. Client -> MCP (Authorize) -> MCP redirects to Provider (with MCP callback URL)
|
|
11
|
+
* 2. Provider -> MCP (Callback) -> MCP exchanges code for tokens
|
|
12
|
+
* 3. MCP redirects to Client (with Internal Code)
|
|
13
|
+
* 4. Client -> MCP (Token) -> MCP returns stored tokens
|
|
14
|
+
*/
|
|
15
|
+
import { randomUUID, createHash } from 'node:crypto';
|
|
16
|
+
import { OAUTH_PATHS } from './constants.js';
|
|
17
|
+
import { escapeHtmlSafe } from './validation-utils.js';
|
|
18
|
+
/**
|
|
19
|
+
* In-memory store for OAuth client registrations
|
|
20
|
+
*/
|
|
21
|
+
export class InMemoryClientsStore {
|
|
22
|
+
clients = new Map();
|
|
23
|
+
async getClient(clientId) {
|
|
24
|
+
return this.clients.get(clientId);
|
|
25
|
+
}
|
|
26
|
+
async registerClient(clientMetadata) {
|
|
27
|
+
this.clients.set(clientMetadata.client_id, clientMetadata);
|
|
28
|
+
return clientMetadata;
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
/**
|
|
32
|
+
* OAuth Provider Adapter for external OAuth servers
|
|
33
|
+
*/
|
|
34
|
+
export class ExternalOAuthProvider {
|
|
35
|
+
config;
|
|
36
|
+
logger;
|
|
37
|
+
_clientsStore;
|
|
38
|
+
// In-memory storage
|
|
39
|
+
authorizationCodes = new Map();
|
|
40
|
+
accessTokens = new Map();
|
|
41
|
+
stateStore = new Map();
|
|
42
|
+
endpointsInitialized = false;
|
|
43
|
+
initializationPromise = null;
|
|
44
|
+
constructor(config, logger) {
|
|
45
|
+
this.config = config;
|
|
46
|
+
this.logger = logger;
|
|
47
|
+
this._clientsStore = new InMemoryClientsStore();
|
|
48
|
+
// Resolve environment variables in OAuth config
|
|
49
|
+
this.config = this.resolveEnvVars(config);
|
|
50
|
+
// Pre-register mcp-proxy-client for VS Code compatibility
|
|
51
|
+
// VS Code doesn't call /oauth/register endpoint before calling /oauth/authorize
|
|
52
|
+
// This client has empty redirect_uris, allowing any redirect URI (validated at runtime)
|
|
53
|
+
const proxyClient = {
|
|
54
|
+
client_id: 'mcp-proxy-client',
|
|
55
|
+
client_secret: 'mcp-proxy-secret',
|
|
56
|
+
redirect_uris: [], // Empty = allow any redirect URI
|
|
57
|
+
grant_types: ['authorization_code', 'refresh_token'],
|
|
58
|
+
response_types: ['code'],
|
|
59
|
+
scope: this.config.scopes ? this.config.scopes.join(' ') : '',
|
|
60
|
+
};
|
|
61
|
+
this._clientsStore.registerClient(proxyClient);
|
|
62
|
+
this.logger.info('Pre-registered mcp-proxy-client for VS Code compatibility');
|
|
63
|
+
}
|
|
64
|
+
/**
|
|
65
|
+
* Lazy initialization of OAuth endpoints (async)
|
|
66
|
+
* Public method to allow HttpTransport to ensure initialization before client validation
|
|
67
|
+
*/
|
|
68
|
+
async ensureEndpointsInitialized() {
|
|
69
|
+
if (this.endpointsInitialized) {
|
|
70
|
+
return;
|
|
71
|
+
}
|
|
72
|
+
// Prevent concurrent initializations
|
|
73
|
+
if (this.initializationPromise) {
|
|
74
|
+
return this.initializationPromise;
|
|
75
|
+
}
|
|
76
|
+
this.initializationPromise = (async () => {
|
|
77
|
+
// Register default client BEFORE deriving endpoints
|
|
78
|
+
// This ensures the client is available immediately, even if endpoint derivation fails
|
|
79
|
+
// The client_id from config should be registered as soon as possible to avoid
|
|
80
|
+
// race conditions where /oauth/authorize is called before initialization completes
|
|
81
|
+
if (this.config.client_id) {
|
|
82
|
+
// Allow localhost and configured redirect_uri for default client
|
|
83
|
+
const allowedUris = [];
|
|
84
|
+
if (this.config.redirect_uri) {
|
|
85
|
+
allowedUris.push(this.config.redirect_uri);
|
|
86
|
+
}
|
|
87
|
+
// Also allow common localhost patterns for development/testing
|
|
88
|
+
allowedUris.push('http://localhost:3003/oauth/callback');
|
|
89
|
+
allowedUris.push('http://127.0.0.1:3003/oauth/callback');
|
|
90
|
+
const defaultClient = {
|
|
91
|
+
client_id: this.config.client_id,
|
|
92
|
+
client_secret: this.config.client_secret,
|
|
93
|
+
redirect_uris: allowedUris,
|
|
94
|
+
grant_types: ['authorization_code', 'refresh_token'],
|
|
95
|
+
response_types: ['code'],
|
|
96
|
+
scope: this.config.scopes ? this.config.scopes.join(' ') : '',
|
|
97
|
+
};
|
|
98
|
+
this._clientsStore.registerClient(defaultClient);
|
|
99
|
+
this.logger.info('Registered default OAuth client', {
|
|
100
|
+
clientId: this.config.client_id,
|
|
101
|
+
redirectUris: allowedUris
|
|
102
|
+
});
|
|
103
|
+
}
|
|
104
|
+
// Derive endpoints from issuer if needed
|
|
105
|
+
this.config = await this.deriveEndpointsFromIssuer(this.config);
|
|
106
|
+
// Validate that we have required endpoints
|
|
107
|
+
if (!this.config.authorization_endpoint || !this.config.token_endpoint) {
|
|
108
|
+
throw new Error('OAuth config must provide either issuer OR both authorization_endpoint and token_endpoint');
|
|
109
|
+
}
|
|
110
|
+
this.logger.info('ExternalOAuthProvider initialized', {
|
|
111
|
+
authEndpoint: this.config.authorization_endpoint,
|
|
112
|
+
tokenEndpoint: this.config.token_endpoint,
|
|
113
|
+
hasClientId: !!this.config.client_id,
|
|
114
|
+
scopes: this.config.scopes || [],
|
|
115
|
+
});
|
|
116
|
+
this.endpointsInitialized = true;
|
|
117
|
+
})();
|
|
118
|
+
return this.initializationPromise;
|
|
119
|
+
}
|
|
120
|
+
get clientsStore() {
|
|
121
|
+
return this._clientsStore;
|
|
122
|
+
}
|
|
123
|
+
get authorizationEndpoint() {
|
|
124
|
+
// May be undefined before ensureEndpointsInitialized() is called
|
|
125
|
+
// when OAuth config provides issuer instead of explicit endpoints
|
|
126
|
+
return this.config.authorization_endpoint;
|
|
127
|
+
}
|
|
128
|
+
get redirectUri() {
|
|
129
|
+
return this.config.redirect_uri;
|
|
130
|
+
}
|
|
131
|
+
get scopes() {
|
|
132
|
+
return this.config.scopes || [];
|
|
133
|
+
}
|
|
134
|
+
/**
|
|
135
|
+
* Fetch OAuth Authorization Server Metadata (RFC 8414)
|
|
136
|
+
*/
|
|
137
|
+
async fetchOAuthMetadata(issuerUrl) {
|
|
138
|
+
try {
|
|
139
|
+
// Use URL constructor to properly handle trailing slashes
|
|
140
|
+
const metadataUrl = new URL(OAUTH_PATHS.WELL_KNOWN_AUTHORIZATION_SERVER, issuerUrl).toString();
|
|
141
|
+
const response = await fetch(metadataUrl, {
|
|
142
|
+
headers: { 'Accept': 'application/json' },
|
|
143
|
+
signal: AbortSignal.timeout(5000), // 5 second timeout
|
|
144
|
+
});
|
|
145
|
+
if (!response.ok) {
|
|
146
|
+
return null;
|
|
147
|
+
}
|
|
148
|
+
const metadata = await response.json();
|
|
149
|
+
return {
|
|
150
|
+
authorization_endpoint: metadata.authorization_endpoint,
|
|
151
|
+
token_endpoint: metadata.token_endpoint,
|
|
152
|
+
};
|
|
153
|
+
}
|
|
154
|
+
catch (error) {
|
|
155
|
+
this.logger.debug('OAuth metadata fetch failed', { issuerUrl, error });
|
|
156
|
+
return null;
|
|
157
|
+
}
|
|
158
|
+
}
|
|
159
|
+
/**
|
|
160
|
+
* Resolve environment variable references in OAuth config
|
|
161
|
+
*/
|
|
162
|
+
resolveEnvVars(config) {
|
|
163
|
+
const resolve = (value) => {
|
|
164
|
+
if (!value)
|
|
165
|
+
return value;
|
|
166
|
+
const match = value.match(/^\$\{env:([^}]+)\}$/);
|
|
167
|
+
if (match) {
|
|
168
|
+
const envVar = match[1];
|
|
169
|
+
const envValue = process.env[envVar];
|
|
170
|
+
if (!envValue) {
|
|
171
|
+
throw new Error(`Environment variable ${envVar} not found (referenced in OAuth config)`);
|
|
172
|
+
}
|
|
173
|
+
return envValue;
|
|
174
|
+
}
|
|
175
|
+
return value;
|
|
176
|
+
};
|
|
177
|
+
return {
|
|
178
|
+
...config,
|
|
179
|
+
issuer: resolve(config.issuer),
|
|
180
|
+
authorization_endpoint: resolve(config.authorization_endpoint) || config.authorization_endpoint,
|
|
181
|
+
token_endpoint: resolve(config.token_endpoint) || config.token_endpoint,
|
|
182
|
+
client_id: resolve(config.client_id),
|
|
183
|
+
client_secret: resolve(config.client_secret),
|
|
184
|
+
redirect_uri: resolve(config.redirect_uri),
|
|
185
|
+
registration_endpoint: resolve(config.registration_endpoint),
|
|
186
|
+
introspection_endpoint: resolve(config.introspection_endpoint),
|
|
187
|
+
revocation_endpoint: resolve(config.revocation_endpoint),
|
|
188
|
+
};
|
|
189
|
+
}
|
|
190
|
+
/**
|
|
191
|
+
* Derive OAuth endpoints from issuer if needed
|
|
192
|
+
*/
|
|
193
|
+
async deriveEndpointsFromIssuer(config) {
|
|
194
|
+
// If both endpoints are explicitly provided, no need to derive
|
|
195
|
+
if (config.authorization_endpoint && config.token_endpoint) {
|
|
196
|
+
return config;
|
|
197
|
+
}
|
|
198
|
+
// If issuer is not provided, we can't derive
|
|
199
|
+
if (!config.issuer) {
|
|
200
|
+
if (!config.authorization_endpoint || !config.token_endpoint) {
|
|
201
|
+
throw new Error('OAuth config must provide either issuer OR both authorization_endpoint and token_endpoint');
|
|
202
|
+
}
|
|
203
|
+
return config;
|
|
204
|
+
}
|
|
205
|
+
const issuer = config.issuer;
|
|
206
|
+
this.logger.info('Deriving OAuth endpoints from issuer', { issuer });
|
|
207
|
+
// Try to fetch OAuth metadata
|
|
208
|
+
const metadata = await this.fetchOAuthMetadata(issuer);
|
|
209
|
+
if (metadata) {
|
|
210
|
+
this.logger.info('Successfully discovered OAuth endpoints', {
|
|
211
|
+
authorization_endpoint: metadata.authorization_endpoint,
|
|
212
|
+
token_endpoint: metadata.token_endpoint,
|
|
213
|
+
});
|
|
214
|
+
return {
|
|
215
|
+
...config,
|
|
216
|
+
authorization_endpoint: config.authorization_endpoint || metadata.authorization_endpoint,
|
|
217
|
+
token_endpoint: config.token_endpoint || metadata.token_endpoint,
|
|
218
|
+
};
|
|
219
|
+
}
|
|
220
|
+
// Fallback to standard OAuth paths
|
|
221
|
+
this.logger.info('OAuth metadata fetch failed, using standard OAuth paths', { issuer });
|
|
222
|
+
return {
|
|
223
|
+
...config,
|
|
224
|
+
authorization_endpoint: config.authorization_endpoint || `${issuer}/oauth/authorize`,
|
|
225
|
+
token_endpoint: config.token_endpoint || `${issuer}/oauth/token`,
|
|
226
|
+
};
|
|
227
|
+
}
|
|
228
|
+
/**
|
|
229
|
+
* Begin authorization flow
|
|
230
|
+
* Stores state and redirects to External Provider with MCP Callback URI
|
|
231
|
+
*/
|
|
232
|
+
async authorize(client, params, res) {
|
|
233
|
+
await this.ensureEndpointsInitialized();
|
|
234
|
+
this.logger.info('Starting OAuth authorization', {
|
|
235
|
+
clientId: client.client_id,
|
|
236
|
+
scopes: params.scopes,
|
|
237
|
+
redirectUri: params.redirectUri,
|
|
238
|
+
registeredUris: client.redirect_uris,
|
|
239
|
+
});
|
|
240
|
+
// Validate redirect URI
|
|
241
|
+
if (client.redirect_uris && client.redirect_uris.length > 0 && !client.redirect_uris.includes(params.redirectUri)) {
|
|
242
|
+
this.logger.error('Invalid redirect URI', undefined, {
|
|
243
|
+
providedUri: params.redirectUri,
|
|
244
|
+
registeredUris: client.redirect_uris,
|
|
245
|
+
});
|
|
246
|
+
throw new Error('Unregistered redirect_uri');
|
|
247
|
+
}
|
|
248
|
+
const stateToken = randomUUID();
|
|
249
|
+
this.stateStore.set(stateToken, {
|
|
250
|
+
clientRedirectUri: params.redirectUri,
|
|
251
|
+
codeChallenge: params.codeChallenge,
|
|
252
|
+
originalState: params.state,
|
|
253
|
+
clientId: client.client_id,
|
|
254
|
+
scopes: params.scopes,
|
|
255
|
+
});
|
|
256
|
+
const authUrl = new URL(this.config.authorization_endpoint);
|
|
257
|
+
const clientId = this.config.client_id || client.client_id;
|
|
258
|
+
if (!this.config.redirect_uri) {
|
|
259
|
+
throw new Error('MCP4_OAUTH_REDIRECT_URI must be configured');
|
|
260
|
+
}
|
|
261
|
+
const callbackUri = this.config.redirect_uri;
|
|
262
|
+
authUrl.searchParams.set('client_id', clientId);
|
|
263
|
+
authUrl.searchParams.set('redirect_uri', callbackUri);
|
|
264
|
+
authUrl.searchParams.set('response_type', 'code');
|
|
265
|
+
authUrl.searchParams.set('state', stateToken);
|
|
266
|
+
if (params.scopes && params.scopes.length > 0) {
|
|
267
|
+
authUrl.searchParams.set('scope', params.scopes.join(' '));
|
|
268
|
+
}
|
|
269
|
+
else if (this.config.scopes && this.config.scopes.length > 0) {
|
|
270
|
+
authUrl.searchParams.set('scope', this.config.scopes.join(' '));
|
|
271
|
+
}
|
|
272
|
+
// NOTE: Do NOT forward PKCE parameters to external provider
|
|
273
|
+
// The MCP server acts as an OAuth proxy with client_secret (confidential client)
|
|
274
|
+
// PKCE is used only between Cursor <-> MCP, not between MCP <-> External Provider
|
|
275
|
+
// If we forwarded code_challenge, we would need code_verifier which only Cursor has
|
|
276
|
+
this.logger.info('Redirecting to external OAuth provider', {
|
|
277
|
+
authUrl: authUrl.toString(),
|
|
278
|
+
callbackUri,
|
|
279
|
+
stateToken,
|
|
280
|
+
hasClientSecret: !!this.config.client_secret,
|
|
281
|
+
});
|
|
282
|
+
res.redirect(authUrl.toString());
|
|
283
|
+
}
|
|
284
|
+
/**
|
|
285
|
+
* Handle callback from External Provider
|
|
286
|
+
* Exchanges code for tokens and redirects to Client with Internal Code
|
|
287
|
+
*/
|
|
288
|
+
async handleCallback(req, res) {
|
|
289
|
+
await this.ensureEndpointsInitialized();
|
|
290
|
+
const { code, state, error } = req.query;
|
|
291
|
+
if (error) {
|
|
292
|
+
this.logger.error('OAuth callback error', undefined, { error, state });
|
|
293
|
+
// Sanitize error messages to prevent XSS
|
|
294
|
+
const safeError = escapeHtmlSafe(error);
|
|
295
|
+
res.status(400);
|
|
296
|
+
res.json({
|
|
297
|
+
error: safeError,
|
|
298
|
+
error_description: `Authorization failed: ${safeError}`
|
|
299
|
+
});
|
|
300
|
+
return;
|
|
301
|
+
}
|
|
302
|
+
if (!code || typeof code !== 'string') {
|
|
303
|
+
res.status(400).send('Missing authorization code');
|
|
304
|
+
return;
|
|
305
|
+
}
|
|
306
|
+
if (!state || typeof state !== 'string') {
|
|
307
|
+
res.status(400).send('Missing state parameter');
|
|
308
|
+
return;
|
|
309
|
+
}
|
|
310
|
+
const storedState = this.stateStore.get(state);
|
|
311
|
+
if (!storedState) {
|
|
312
|
+
res.status(400).send('Invalid or expired state');
|
|
313
|
+
return;
|
|
314
|
+
}
|
|
315
|
+
// Clean up state
|
|
316
|
+
this.stateStore.delete(state);
|
|
317
|
+
try {
|
|
318
|
+
// Exchange External Code for Tokens
|
|
319
|
+
const tokens = await this.exchangeCodeWithProvider(code, undefined, this.config.redirect_uri);
|
|
320
|
+
// Generate Internal Code
|
|
321
|
+
const internalCode = randomUUID();
|
|
322
|
+
// Store Internal Code -> Tokens mapping
|
|
323
|
+
const client = await this._clientsStore.getClient(storedState.clientId);
|
|
324
|
+
if (!client)
|
|
325
|
+
throw new Error('Client not found');
|
|
326
|
+
this.authorizationCodes.set(internalCode, {
|
|
327
|
+
client,
|
|
328
|
+
params: {
|
|
329
|
+
redirectUri: storedState.clientRedirectUri,
|
|
330
|
+
codeChallenge: storedState.codeChallenge,
|
|
331
|
+
scopes: storedState.scopes || [],
|
|
332
|
+
state: storedState.originalState
|
|
333
|
+
},
|
|
334
|
+
createdAt: Date.now(),
|
|
335
|
+
tokens
|
|
336
|
+
});
|
|
337
|
+
// Redirect to Client
|
|
338
|
+
const clientUrl = new URL(storedState.clientRedirectUri);
|
|
339
|
+
clientUrl.searchParams.set('code', internalCode);
|
|
340
|
+
if (storedState.originalState) {
|
|
341
|
+
clientUrl.searchParams.set('state', storedState.originalState);
|
|
342
|
+
}
|
|
343
|
+
this.logger.info('Redirecting to client with internal code', {
|
|
344
|
+
clientUrl: clientUrl.toString(),
|
|
345
|
+
internalCode
|
|
346
|
+
});
|
|
347
|
+
res.redirect(clientUrl.toString());
|
|
348
|
+
}
|
|
349
|
+
catch (err) {
|
|
350
|
+
this.logger.error('Callback handling failed', err);
|
|
351
|
+
res.status(500).send('Internal Server Error during token exchange');
|
|
352
|
+
}
|
|
353
|
+
}
|
|
354
|
+
/**
|
|
355
|
+
* Get code challenge for authorization code (Internal)
|
|
356
|
+
*/
|
|
357
|
+
async challengeForAuthorizationCode(client, authorizationCode) {
|
|
358
|
+
const codeData = this.authorizationCodes.get(authorizationCode);
|
|
359
|
+
if (!codeData) {
|
|
360
|
+
throw new Error('Invalid authorization code');
|
|
361
|
+
}
|
|
362
|
+
if (codeData.client.client_id !== client.client_id) {
|
|
363
|
+
throw new Error('Authorization code was not issued to this client');
|
|
364
|
+
}
|
|
365
|
+
return codeData.params.codeChallenge;
|
|
366
|
+
}
|
|
367
|
+
/**
|
|
368
|
+
* Exchange authorization code for access token (Internal)
|
|
369
|
+
*/
|
|
370
|
+
async exchangeAuthorizationCode(client, authorizationCode, codeVerifier, redirectUri, resource) {
|
|
371
|
+
await this.ensureEndpointsInitialized();
|
|
372
|
+
this.logger.info('Exchanging internal authorization code', {
|
|
373
|
+
clientId: client.client_id,
|
|
374
|
+
});
|
|
375
|
+
const codeData = this.authorizationCodes.get(authorizationCode);
|
|
376
|
+
if (!codeData) {
|
|
377
|
+
throw new Error('Invalid authorization code');
|
|
378
|
+
}
|
|
379
|
+
if (codeData.client.client_id !== client.client_id) {
|
|
380
|
+
throw new Error('Authorization code was not issued to this client');
|
|
381
|
+
}
|
|
382
|
+
// Validate expiration (5 minutes)
|
|
383
|
+
const codeAge = Date.now() - codeData.createdAt;
|
|
384
|
+
const EXPIRATION_MS = 5 * 60 * 1000; // 5 minutes
|
|
385
|
+
if (codeAge > EXPIRATION_MS) {
|
|
386
|
+
this.authorizationCodes.delete(authorizationCode);
|
|
387
|
+
throw new Error('Authorization code expired');
|
|
388
|
+
}
|
|
389
|
+
// Validate PKCE if code challenge was provided
|
|
390
|
+
if (codeData.params.codeChallenge) {
|
|
391
|
+
if (!codeVerifier) {
|
|
392
|
+
throw new Error('code_verifier is required for PKCE');
|
|
393
|
+
}
|
|
394
|
+
// Verify code challenge (S256 method)
|
|
395
|
+
const hash = createHash('sha256').update(codeVerifier).digest('base64url');
|
|
396
|
+
if (hash !== codeData.params.codeChallenge) {
|
|
397
|
+
throw new Error('Invalid code_verifier');
|
|
398
|
+
}
|
|
399
|
+
}
|
|
400
|
+
if (!codeData.tokens) {
|
|
401
|
+
throw new Error('No tokens associated with this code');
|
|
402
|
+
}
|
|
403
|
+
// Delete authorization code (single use)
|
|
404
|
+
this.authorizationCodes.delete(authorizationCode);
|
|
405
|
+
// Store access token for validation
|
|
406
|
+
const tokenData = {
|
|
407
|
+
token: codeData.tokens.access_token,
|
|
408
|
+
clientId: client.client_id,
|
|
409
|
+
scopes: codeData.params.scopes || this.config.scopes || [],
|
|
410
|
+
expiresAt: codeData.tokens.expires_in
|
|
411
|
+
? Date.now() + codeData.tokens.expires_in * 1000
|
|
412
|
+
: undefined,
|
|
413
|
+
resource,
|
|
414
|
+
};
|
|
415
|
+
this.accessTokens.set(codeData.tokens.access_token, tokenData);
|
|
416
|
+
return codeData.tokens;
|
|
417
|
+
}
|
|
418
|
+
/**
|
|
419
|
+
* Exchange authorization code with external OAuth provider
|
|
420
|
+
*/
|
|
421
|
+
async exchangeCodeWithProvider(code, codeVerifier, redirectUri) {
|
|
422
|
+
const tokenUrl = this.config.token_endpoint;
|
|
423
|
+
const body = new URLSearchParams({
|
|
424
|
+
grant_type: 'authorization_code',
|
|
425
|
+
code,
|
|
426
|
+
redirect_uri: redirectUri,
|
|
427
|
+
});
|
|
428
|
+
if (codeVerifier) {
|
|
429
|
+
body.set('code_verifier', codeVerifier);
|
|
430
|
+
}
|
|
431
|
+
if (this.config.client_id) {
|
|
432
|
+
body.set('client_id', this.config.client_id);
|
|
433
|
+
}
|
|
434
|
+
if (this.config.client_secret) {
|
|
435
|
+
body.set('client_secret', this.config.client_secret);
|
|
436
|
+
}
|
|
437
|
+
this.logger.debug('Exchanging code with external provider', { tokenUrl });
|
|
438
|
+
const response = await fetch(tokenUrl, {
|
|
439
|
+
method: 'POST',
|
|
440
|
+
headers: {
|
|
441
|
+
'Content-Type': 'application/x-www-form-urlencoded',
|
|
442
|
+
'Accept': 'application/json',
|
|
443
|
+
},
|
|
444
|
+
body: body.toString(),
|
|
445
|
+
});
|
|
446
|
+
if (!response.ok) {
|
|
447
|
+
const errorText = await response.text();
|
|
448
|
+
this.logger.error('Token exchange failed', undefined, {
|
|
449
|
+
httpStatus: response.status,
|
|
450
|
+
errorMessage: errorText,
|
|
451
|
+
});
|
|
452
|
+
throw new Error(`Token exchange failed: ${response.status} ${errorText}`);
|
|
453
|
+
}
|
|
454
|
+
const tokenResponse = await response.json();
|
|
455
|
+
return tokenResponse;
|
|
456
|
+
}
|
|
457
|
+
async exchangeRefreshToken(client, refreshToken, scopes, resource) {
|
|
458
|
+
await this.ensureEndpointsInitialized();
|
|
459
|
+
this.logger.info('Exchanging refresh token', { clientId: client.client_id });
|
|
460
|
+
const tokenUrl = this.config.token_endpoint;
|
|
461
|
+
const body = new URLSearchParams({
|
|
462
|
+
grant_type: 'refresh_token',
|
|
463
|
+
refresh_token: refreshToken,
|
|
464
|
+
});
|
|
465
|
+
if (scopes && scopes.length > 0) {
|
|
466
|
+
body.set('scope', scopes.join(' '));
|
|
467
|
+
}
|
|
468
|
+
if (this.config.client_id) {
|
|
469
|
+
body.set('client_id', this.config.client_id);
|
|
470
|
+
}
|
|
471
|
+
if (this.config.client_secret) {
|
|
472
|
+
body.set('client_secret', this.config.client_secret);
|
|
473
|
+
}
|
|
474
|
+
const response = await fetch(tokenUrl, {
|
|
475
|
+
method: 'POST',
|
|
476
|
+
headers: {
|
|
477
|
+
'Content-Type': 'application/x-www-form-urlencoded',
|
|
478
|
+
'Accept': 'application/json',
|
|
479
|
+
},
|
|
480
|
+
body: body.toString(),
|
|
481
|
+
});
|
|
482
|
+
if (!response.ok) {
|
|
483
|
+
const errorText = await response.text();
|
|
484
|
+
this.logger.error('Refresh token exchange failed', undefined, {
|
|
485
|
+
httpStatus: response.status,
|
|
486
|
+
errorMessage: errorText,
|
|
487
|
+
});
|
|
488
|
+
throw new Error(`Refresh token exchange failed: ${response.status}`);
|
|
489
|
+
}
|
|
490
|
+
const tokenResponse = await response.json();
|
|
491
|
+
const tokenData = {
|
|
492
|
+
token: tokenResponse.access_token,
|
|
493
|
+
clientId: client.client_id,
|
|
494
|
+
scopes: scopes || this.config.scopes || [],
|
|
495
|
+
expiresAt: tokenResponse.expires_in
|
|
496
|
+
? Date.now() + tokenResponse.expires_in * 1000
|
|
497
|
+
: undefined,
|
|
498
|
+
resource,
|
|
499
|
+
};
|
|
500
|
+
this.accessTokens.set(tokenResponse.access_token, tokenData);
|
|
501
|
+
return tokenResponse;
|
|
502
|
+
}
|
|
503
|
+
async verifyAccessToken(token) {
|
|
504
|
+
const tokenData = this.accessTokens.get(token);
|
|
505
|
+
if (!tokenData) {
|
|
506
|
+
if (this.config.introspection_endpoint) {
|
|
507
|
+
return await this.introspectToken(token);
|
|
508
|
+
}
|
|
509
|
+
throw new Error('Invalid or expired token');
|
|
510
|
+
}
|
|
511
|
+
if (tokenData.expiresAt && tokenData.expiresAt < Date.now()) {
|
|
512
|
+
this.accessTokens.delete(token);
|
|
513
|
+
throw new Error('Token expired');
|
|
514
|
+
}
|
|
515
|
+
return {
|
|
516
|
+
token,
|
|
517
|
+
clientId: tokenData.clientId,
|
|
518
|
+
scopes: tokenData.scopes,
|
|
519
|
+
expiresAt: tokenData.expiresAt ? Math.floor(tokenData.expiresAt / 1000) : undefined,
|
|
520
|
+
resource: tokenData.resource,
|
|
521
|
+
};
|
|
522
|
+
}
|
|
523
|
+
async introspectToken(token) {
|
|
524
|
+
const introspectionUrl = this.config.introspection_endpoint;
|
|
525
|
+
if (!introspectionUrl) {
|
|
526
|
+
throw new Error('Introspection endpoint not configured');
|
|
527
|
+
}
|
|
528
|
+
const body = new URLSearchParams({ token });
|
|
529
|
+
if (this.config.client_id) {
|
|
530
|
+
body.set('client_id', this.config.client_id);
|
|
531
|
+
}
|
|
532
|
+
if (this.config.client_secret) {
|
|
533
|
+
body.set('client_secret', this.config.client_secret);
|
|
534
|
+
}
|
|
535
|
+
const response = await fetch(introspectionUrl, {
|
|
536
|
+
method: 'POST',
|
|
537
|
+
headers: {
|
|
538
|
+
'Content-Type': 'application/x-www-form-urlencoded',
|
|
539
|
+
'Accept': 'application/json',
|
|
540
|
+
},
|
|
541
|
+
body: body.toString(),
|
|
542
|
+
});
|
|
543
|
+
if (!response.ok) {
|
|
544
|
+
throw new Error(`Token introspection failed: ${response.status}`);
|
|
545
|
+
}
|
|
546
|
+
const introspectionResponse = await response.json();
|
|
547
|
+
if (!introspectionResponse.active) {
|
|
548
|
+
throw new Error('Token is not active');
|
|
549
|
+
}
|
|
550
|
+
return {
|
|
551
|
+
token,
|
|
552
|
+
clientId: introspectionResponse.client_id || 'unknown',
|
|
553
|
+
scopes: introspectionResponse.scope ? introspectionResponse.scope.split(' ') : [],
|
|
554
|
+
expiresAt: introspectionResponse.exp,
|
|
555
|
+
resource: introspectionResponse.aud ? new URL(introspectionResponse.aud) : undefined,
|
|
556
|
+
};
|
|
557
|
+
}
|
|
558
|
+
async revokeToken(client, request) {
|
|
559
|
+
this.logger.info('Revoking token', { clientId: client.client_id });
|
|
560
|
+
this.accessTokens.delete(request.token);
|
|
561
|
+
if (this.config.revocation_endpoint) {
|
|
562
|
+
await this.revokeTokenWithProvider(request.token);
|
|
563
|
+
}
|
|
564
|
+
}
|
|
565
|
+
async revokeTokenWithProvider(token) {
|
|
566
|
+
const revocationUrl = this.config.revocation_endpoint;
|
|
567
|
+
if (!revocationUrl)
|
|
568
|
+
return;
|
|
569
|
+
const body = new URLSearchParams({ token });
|
|
570
|
+
if (this.config.client_id) {
|
|
571
|
+
body.set('client_id', this.config.client_id);
|
|
572
|
+
}
|
|
573
|
+
if (this.config.client_secret) {
|
|
574
|
+
body.set('client_secret', this.config.client_secret);
|
|
575
|
+
}
|
|
576
|
+
const response = await fetch(revocationUrl, {
|
|
577
|
+
method: 'POST',
|
|
578
|
+
headers: {
|
|
579
|
+
'Content-Type': 'application/x-www-form-urlencoded',
|
|
580
|
+
},
|
|
581
|
+
body: body.toString(),
|
|
582
|
+
});
|
|
583
|
+
if (!response.ok) {
|
|
584
|
+
this.logger.warn('Token revocation failed', { status: response.status });
|
|
585
|
+
}
|
|
586
|
+
}
|
|
587
|
+
}
|
|
588
|
+
//# sourceMappingURL=oauth-provider.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"oauth-provider.js","sourceRoot":"","sources":["../../src/oauth-provider.ts"],"names":[],"mappings":"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"}
|
|
@@ -8,6 +8,7 @@ import type { OperationInfo, PathInfo } from './types/openapi.js';
|
|
|
8
8
|
export declare class OpenAPIParser {
|
|
9
9
|
private spec?;
|
|
10
10
|
private index?;
|
|
11
|
+
private schemaCache;
|
|
11
12
|
load(specPath: string): Promise<void>;
|
|
12
13
|
/**
|
|
13
14
|
* Build search index from OpenAPI spec
|
|
@@ -27,9 +28,24 @@ export declare class OpenAPIParser {
|
|
|
27
28
|
private resolveParameter;
|
|
28
29
|
private extractRequestBody;
|
|
29
30
|
private extractSchema;
|
|
31
|
+
private resolveSchema;
|
|
32
|
+
private mergeSchemaInfo;
|
|
33
|
+
private cloneSchemaInfo;
|
|
30
34
|
getOperation(operationId: string): OperationInfo | undefined;
|
|
31
35
|
getPath(path: string): PathInfo | undefined;
|
|
32
36
|
getBaseUrl(): string;
|
|
37
|
+
/**
|
|
38
|
+
* Get resource metadata from OpenAPI spec
|
|
39
|
+
*
|
|
40
|
+
* Why: Used for OAuth 2.0 Protected Resource Metadata (RFC 8707)
|
|
41
|
+
* to provide human-readable name and documentation URL for the API.
|
|
42
|
+
*
|
|
43
|
+
* Returns undefined for fields not present in spec.
|
|
44
|
+
*/
|
|
45
|
+
getResourceMetadata(): {
|
|
46
|
+
name?: string;
|
|
47
|
+
documentation?: string;
|
|
48
|
+
};
|
|
33
49
|
getAllOperations(): OperationInfo[];
|
|
34
50
|
/**
|
|
35
51
|
* Get first security scheme from OpenAPI spec
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"openapi-parser.d.ts","sourceRoot":"","sources":["../../src/openapi-parser.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAMH,OAAO,KAAK,EAAgB,aAAa,EAAiB,QAAQ,EAA+B,MAAM,oBAAoB,CAAC;AAE5H,qBAAa,aAAa;IACxB,OAAO,CAAC,IAAI,CAAC,CAAqB;IAClC,OAAO,CAAC,KAAK,CAAC,CAAe;
|
|
1
|
+
{"version":3,"file":"openapi-parser.d.ts","sourceRoot":"","sources":["../../src/openapi-parser.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAMH,OAAO,KAAK,EAAgB,aAAa,EAAiB,QAAQ,EAA+B,MAAM,oBAAoB,CAAC;AAE5H,qBAAa,aAAa;IACxB,OAAO,CAAC,IAAI,CAAC,CAAqB;IAClC,OAAO,CAAC,KAAK,CAAC,CAAe;IAC7B,OAAO,CAAC,WAAW,CAAiC;IAE9C,IAAI,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAc3C;;;;;OAKG;IACH,OAAO,CAAC,UAAU;IAmClB,OAAO,CAAC,oBAAoB;IAiB5B,OAAO,CAAC,iBAAiB;IAqBzB;;;;;OAKG;IACH,OAAO,CAAC,gBAAgB;IAaxB,OAAO,CAAC,kBAAkB;IAoB1B,OAAO,CAAC,aAAa;IAsDrB,OAAO,CAAC,aAAa;IAyCrB,OAAO,CAAC,eAAe;IA4BvB,OAAO,CAAC,eAAe;IAwCvB,YAAY,CAAC,WAAW,EAAE,MAAM,GAAG,aAAa,GAAG,SAAS;IAI5D,OAAO,CAAC,IAAI,EAAE,MAAM,GAAG,QAAQ,GAAG,SAAS;IAI3C,UAAU,IAAI,MAAM;IAKpB;;;;;;;OAOG;IACH,mBAAmB,IAAI;QACrB,IAAI,CAAC,EAAE,MAAM,CAAC;QACd,aAAa,CAAC,EAAE,MAAM,CAAC;KACxB;IAOD,gBAAgB,IAAI,aAAa,EAAE;IAInC;;;;;;;OAOG;IACH,iBAAiB,IAAI;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,MAAM,CAAC,EAAE,MAAM,CAAC;QAAC,IAAI,CAAC,EAAE,MAAM,CAAC;QAAC,EAAE,CAAC,EAAE,MAAM,CAAA;KAAE,GAAG,SAAS;CAoD/F"}
|