mcp-use 1.6.3-canary.0 → 1.7.0-canary.2
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/dist/.tsbuildinfo +1 -1
- package/dist/chunk-3R5PDYIN.js +403 -0
- package/dist/{chunk-BWOTID2D.js → chunk-AGKMD2ZM.js} +7 -350
- package/dist/{chunk-SJEHVCPM.js → chunk-BG2APH43.js} +120 -26
- package/dist/{chunk-YURRUCIM.js → chunk-CPG2WZUL.js} +9 -11
- package/dist/chunk-F4UHAA5L.js +854 -0
- package/dist/chunk-JQKKMUCT.js +0 -0
- package/dist/chunk-MTHLLDCX.js +97 -0
- package/dist/{chunk-MCF5P6GJ.js → chunk-S6K5QZBJ.js} +739 -29
- package/dist/{display-YIYC6WJE.js → display-A5IEINAP.js} +79 -17
- package/dist/index.cjs +1055 -136
- package/dist/index.js +14 -10
- package/dist/{langfuse-C4HKZ3NL.js → langfuse-N5Y5BSXK.js} +1 -1
- package/dist/oauth-U4NNKN4B.js +30 -0
- package/dist/src/agents/display.d.ts.map +1 -1
- package/dist/src/agents/index.cjs +854 -78
- package/dist/src/agents/index.js +3 -2
- package/dist/src/auth/browser-provider.d.ts +2 -0
- package/dist/src/auth/browser-provider.d.ts.map +1 -1
- package/dist/src/auth/callback.d.ts.map +1 -1
- package/dist/src/auth/index.cjs +421 -0
- package/dist/src/auth/index.js +10 -0
- package/dist/src/auth/types.d.ts +3 -1
- package/dist/src/auth/types.d.ts.map +1 -1
- package/dist/src/browser.cjs +924 -98
- package/dist/src/browser.js +8 -5
- package/dist/src/connectors/base.d.ts +52 -121
- package/dist/src/connectors/base.d.ts.map +1 -1
- package/dist/src/connectors/http.d.ts.map +1 -1
- package/dist/src/managers/server_manager.d.ts.map +1 -1
- package/dist/src/managers/tools/acquire_active_mcp_server.d.ts +2 -2
- package/dist/src/managers/tools/acquire_active_mcp_server.d.ts.map +1 -1
- package/dist/src/managers/tools/add_server_from_config.d.ts +1 -7
- package/dist/src/managers/tools/add_server_from_config.d.ts.map +1 -1
- package/dist/src/managers/tools/connect_mcp_server.d.ts +2 -10
- package/dist/src/managers/tools/connect_mcp_server.d.ts.map +1 -1
- package/dist/src/managers/tools/list_mcp_servers.d.ts +2 -2
- package/dist/src/managers/tools/list_mcp_servers.d.ts.map +1 -1
- package/dist/src/managers/tools/release_mcp_server_connection.d.ts +2 -2
- package/dist/src/managers/tools/release_mcp_server_connection.d.ts.map +1 -1
- package/dist/src/observability/langfuse.d.ts +4 -0
- package/dist/src/observability/langfuse.d.ts.map +1 -1
- package/dist/src/react/McpUseProvider.d.ts.map +1 -1
- package/dist/src/react/index.cjs +189 -41
- package/dist/src/react/index.js +4 -2
- package/dist/src/react/types.d.ts +12 -1
- package/dist/src/react/types.d.ts.map +1 -1
- package/dist/src/react/useMcp.d.ts.map +1 -1
- package/dist/src/server/connect-adapter.d.ts.map +1 -1
- package/dist/src/server/context-storage.d.ts +54 -0
- package/dist/src/server/context-storage.d.ts.map +1 -0
- package/dist/src/server/index.cjs +1413 -418
- package/dist/src/server/index.d.ts +4 -1
- package/dist/src/server/index.d.ts.map +1 -1
- package/dist/src/server/index.js +426 -420
- package/dist/src/server/mcp-server.d.ts +50 -81
- package/dist/src/server/mcp-server.d.ts.map +1 -1
- package/dist/src/server/oauth/index.d.ts +13 -0
- package/dist/src/server/oauth/index.d.ts.map +1 -0
- package/dist/src/server/oauth/middleware.d.ts +19 -0
- package/dist/src/server/oauth/middleware.d.ts.map +1 -0
- package/dist/src/server/oauth/providers/auth0.d.ts +22 -0
- package/dist/src/server/oauth/providers/auth0.d.ts.map +1 -0
- package/dist/src/server/oauth/providers/custom.d.ts +19 -0
- package/dist/src/server/oauth/providers/custom.d.ts.map +1 -0
- package/dist/src/server/oauth/providers/keycloak.d.ts +22 -0
- package/dist/src/server/oauth/providers/keycloak.d.ts.map +1 -0
- package/dist/src/server/oauth/providers/supabase.d.ts +24 -0
- package/dist/src/server/oauth/providers/supabase.d.ts.map +1 -0
- package/dist/src/server/oauth/providers/types.d.ts +138 -0
- package/dist/src/server/oauth/providers/types.d.ts.map +1 -0
- package/dist/src/server/oauth/providers/workos.d.ts +30 -0
- package/dist/src/server/oauth/providers/workos.d.ts.map +1 -0
- package/dist/src/server/oauth/providers.d.ts +208 -0
- package/dist/src/server/oauth/providers.d.ts.map +1 -0
- package/dist/src/server/oauth/routes.d.ts +33 -0
- package/dist/src/server/oauth/routes.d.ts.map +1 -0
- package/dist/src/server/oauth/utils.d.ts +155 -0
- package/dist/src/server/oauth/utils.d.ts.map +1 -0
- package/dist/src/server/types/common.d.ts +47 -0
- package/dist/src/server/types/common.d.ts.map +1 -1
- package/dist/src/server/types/context.d.ts +34 -0
- package/dist/src/server/types/context.d.ts.map +1 -0
- package/dist/src/server/types/index.d.ts +2 -1
- package/dist/src/server/types/index.d.ts.map +1 -1
- package/dist/src/server/types/tool.d.ts +82 -9
- package/dist/src/server/types/tool.d.ts.map +1 -1
- package/dist/src/server/utils/index.d.ts +6 -0
- package/dist/src/server/utils/index.d.ts.map +1 -0
- package/dist/src/server/utils/response-helpers.d.ts +151 -0
- package/dist/src/server/utils/response-helpers.d.ts.map +1 -0
- package/dist/src/server/utils/runtime.d.ts +25 -0
- package/dist/src/server/utils/runtime.d.ts.map +1 -0
- package/dist/src/task_managers/streamable_http.d.ts +1 -0
- package/dist/src/task_managers/streamable_http.d.ts.map +1 -1
- package/dist/src/utils/json-schema-to-zod/JSONSchemaToZod.d.ts +270 -0
- package/dist/src/utils/json-schema-to-zod/JSONSchemaToZod.d.ts.map +1 -0
- package/dist/src/utils/json-schema-to-zod/Type.d.ts +24 -0
- package/dist/src/utils/json-schema-to-zod/Type.d.ts.map +1 -0
- package/dist/src/utils/json-schema-to-zod/index.d.ts +3 -0
- package/dist/src/utils/json-schema-to-zod/index.d.ts.map +1 -0
- package/dist/src/utils/url-sanitize.d.ts +17 -0
- package/dist/src/utils/url-sanitize.d.ts.map +1 -0
- package/dist/tsup.config.d.ts.map +1 -1
- package/package.json +30 -38
|
@@ -0,0 +1,854 @@
|
|
|
1
|
+
import {
|
|
2
|
+
getEnv
|
|
3
|
+
} from "./chunk-MTHLLDCX.js";
|
|
4
|
+
import {
|
|
5
|
+
__name
|
|
6
|
+
} from "./chunk-3GQAWCBQ.js";
|
|
7
|
+
|
|
8
|
+
// src/server/oauth/providers/supabase.ts
|
|
9
|
+
import {
|
|
10
|
+
jwtVerify,
|
|
11
|
+
createRemoteJWKSet,
|
|
12
|
+
decodeProtectedHeader,
|
|
13
|
+
decodeJwt
|
|
14
|
+
} from "jose";
|
|
15
|
+
var SupabaseOAuthProvider = class {
|
|
16
|
+
static {
|
|
17
|
+
__name(this, "SupabaseOAuthProvider");
|
|
18
|
+
}
|
|
19
|
+
config;
|
|
20
|
+
supabaseUrl;
|
|
21
|
+
supabaseAuthUrl;
|
|
22
|
+
issuer;
|
|
23
|
+
jwks = null;
|
|
24
|
+
constructor(config) {
|
|
25
|
+
this.config = config;
|
|
26
|
+
this.supabaseUrl = `https://${config.projectId}.supabase.co`;
|
|
27
|
+
this.supabaseAuthUrl = `${this.supabaseUrl}/auth/v1`;
|
|
28
|
+
this.issuer = `${this.supabaseUrl}/auth/v1`;
|
|
29
|
+
}
|
|
30
|
+
getJWKS() {
|
|
31
|
+
if (!this.jwks) {
|
|
32
|
+
this.jwks = createRemoteJWKSet(
|
|
33
|
+
new URL(`${this.issuer}/.well-known/jwks.json`)
|
|
34
|
+
);
|
|
35
|
+
}
|
|
36
|
+
return this.jwks;
|
|
37
|
+
}
|
|
38
|
+
async verifyToken(token) {
|
|
39
|
+
if (this.config.skipVerification) {
|
|
40
|
+
console.warn(
|
|
41
|
+
"[Supabase OAuth] \u26A0\uFE0F SKIPPING VERIFICATION (DEVELOPMENT MODE)"
|
|
42
|
+
);
|
|
43
|
+
console.warn(
|
|
44
|
+
"[Supabase OAuth] This is NOT secure! Only use for testing!"
|
|
45
|
+
);
|
|
46
|
+
const payload = decodeJwt(token);
|
|
47
|
+
return { payload, protectedHeader: decodeProtectedHeader(token) };
|
|
48
|
+
}
|
|
49
|
+
try {
|
|
50
|
+
const header = decodeProtectedHeader(token);
|
|
51
|
+
if (header.alg === "HS256") {
|
|
52
|
+
if (!this.config.jwtSecret) {
|
|
53
|
+
throw new Error(
|
|
54
|
+
"JWT Secret is required for HS256 tokens. Get it from: Supabase Dashboard \u2192 Project Settings \u2192 API \u2192 JWT Settings"
|
|
55
|
+
);
|
|
56
|
+
}
|
|
57
|
+
const secret = new TextEncoder().encode(this.config.jwtSecret);
|
|
58
|
+
const result = await jwtVerify(token, secret, {
|
|
59
|
+
issuer: this.issuer,
|
|
60
|
+
audience: "authenticated"
|
|
61
|
+
});
|
|
62
|
+
return result;
|
|
63
|
+
} else if (header.alg === "ES256") {
|
|
64
|
+
const result = await jwtVerify(token, this.getJWKS(), {
|
|
65
|
+
issuer: this.issuer,
|
|
66
|
+
audience: "authenticated"
|
|
67
|
+
});
|
|
68
|
+
return result;
|
|
69
|
+
} else {
|
|
70
|
+
throw new Error(`Unsupported algorithm: ${header.alg}`);
|
|
71
|
+
}
|
|
72
|
+
} catch (error) {
|
|
73
|
+
throw new Error(`Supabase JWT verification failed: ${error}`);
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
getUserInfo(payload) {
|
|
77
|
+
return {
|
|
78
|
+
userId: payload.sub || payload.user_id,
|
|
79
|
+
email: payload.email,
|
|
80
|
+
name: payload.user_metadata?.name || payload.user_metadata?.full_name,
|
|
81
|
+
username: payload.user_metadata?.username,
|
|
82
|
+
picture: payload.user_metadata?.avatar_url,
|
|
83
|
+
roles: payload.role ? [payload.role] : [],
|
|
84
|
+
permissions: payload.aal ? [`aal:${payload.aal}`] : [],
|
|
85
|
+
// Include Supabase-specific claims
|
|
86
|
+
aal: payload.aal,
|
|
87
|
+
// Authentication Assurance Level
|
|
88
|
+
amr: payload.amr,
|
|
89
|
+
// Authentication Methods References
|
|
90
|
+
session_id: payload.session_id
|
|
91
|
+
};
|
|
92
|
+
}
|
|
93
|
+
getIssuer() {
|
|
94
|
+
return this.issuer;
|
|
95
|
+
}
|
|
96
|
+
getAuthEndpoint() {
|
|
97
|
+
return `${this.supabaseAuthUrl}/authorize`;
|
|
98
|
+
}
|
|
99
|
+
getTokenEndpoint() {
|
|
100
|
+
return `${this.supabaseAuthUrl}/token`;
|
|
101
|
+
}
|
|
102
|
+
getScopesSupported() {
|
|
103
|
+
return [];
|
|
104
|
+
}
|
|
105
|
+
getGrantTypesSupported() {
|
|
106
|
+
return ["authorization_code", "refresh_token"];
|
|
107
|
+
}
|
|
108
|
+
};
|
|
109
|
+
|
|
110
|
+
// src/server/oauth/providers/auth0.ts
|
|
111
|
+
import { jwtVerify as jwtVerify2, createRemoteJWKSet as createRemoteJWKSet2 } from "jose";
|
|
112
|
+
var Auth0OAuthProvider = class {
|
|
113
|
+
static {
|
|
114
|
+
__name(this, "Auth0OAuthProvider");
|
|
115
|
+
}
|
|
116
|
+
config;
|
|
117
|
+
issuer;
|
|
118
|
+
jwks = null;
|
|
119
|
+
constructor(config) {
|
|
120
|
+
this.config = config;
|
|
121
|
+
this.issuer = `https://${config.domain}`;
|
|
122
|
+
}
|
|
123
|
+
getJWKS() {
|
|
124
|
+
if (!this.jwks) {
|
|
125
|
+
this.jwks = createRemoteJWKSet2(
|
|
126
|
+
new URL(`${this.issuer}/.well-known/jwks.json`)
|
|
127
|
+
);
|
|
128
|
+
}
|
|
129
|
+
return this.jwks;
|
|
130
|
+
}
|
|
131
|
+
async verifyToken(token) {
|
|
132
|
+
if (this.config.verifyJwt === false) {
|
|
133
|
+
console.warn("[Auth0 OAuth] \u26A0\uFE0F JWT verification is disabled");
|
|
134
|
+
console.warn("[Auth0 OAuth] Enable verifyJwt: true for production");
|
|
135
|
+
const parts = token.split(".");
|
|
136
|
+
if (parts.length !== 3) {
|
|
137
|
+
throw new Error("Invalid JWT format");
|
|
138
|
+
}
|
|
139
|
+
const payload = JSON.parse(
|
|
140
|
+
Buffer.from(parts[1], "base64url").toString("utf8")
|
|
141
|
+
);
|
|
142
|
+
return { payload };
|
|
143
|
+
}
|
|
144
|
+
try {
|
|
145
|
+
const result = await jwtVerify2(token, this.getJWKS(), {
|
|
146
|
+
issuer: this.issuer,
|
|
147
|
+
audience: this.config.audience
|
|
148
|
+
});
|
|
149
|
+
return result;
|
|
150
|
+
} catch (error) {
|
|
151
|
+
throw new Error(`Auth0 JWT verification failed: ${error}`);
|
|
152
|
+
}
|
|
153
|
+
}
|
|
154
|
+
getUserInfo(payload) {
|
|
155
|
+
return {
|
|
156
|
+
userId: payload.sub,
|
|
157
|
+
email: payload.email,
|
|
158
|
+
name: payload.name,
|
|
159
|
+
username: payload.username,
|
|
160
|
+
nickname: payload.nickname,
|
|
161
|
+
picture: payload.picture,
|
|
162
|
+
// Auth0 includes permissions directly in the token
|
|
163
|
+
permissions: payload.permissions || [],
|
|
164
|
+
// Auth0 can include roles (if configured)
|
|
165
|
+
roles: payload.roles || payload["https://your-app.com/roles"] || [],
|
|
166
|
+
// Include scope as well
|
|
167
|
+
scopes: payload.scope ? payload.scope.split(" ") : [],
|
|
168
|
+
// Additional Auth0-specific claims
|
|
169
|
+
email_verified: payload.email_verified,
|
|
170
|
+
updated_at: payload.updated_at
|
|
171
|
+
};
|
|
172
|
+
}
|
|
173
|
+
getIssuer() {
|
|
174
|
+
return this.issuer;
|
|
175
|
+
}
|
|
176
|
+
getAuthEndpoint() {
|
|
177
|
+
return `${this.issuer}/authorize`;
|
|
178
|
+
}
|
|
179
|
+
getTokenEndpoint() {
|
|
180
|
+
return `${this.issuer}/oauth/token`;
|
|
181
|
+
}
|
|
182
|
+
getScopesSupported() {
|
|
183
|
+
return ["openid", "profile", "email", "offline_access"];
|
|
184
|
+
}
|
|
185
|
+
getGrantTypesSupported() {
|
|
186
|
+
return ["authorization_code", "refresh_token"];
|
|
187
|
+
}
|
|
188
|
+
};
|
|
189
|
+
|
|
190
|
+
// src/server/oauth/providers/keycloak.ts
|
|
191
|
+
import { jwtVerify as jwtVerify3, createRemoteJWKSet as createRemoteJWKSet3 } from "jose";
|
|
192
|
+
var KeycloakOAuthProvider = class {
|
|
193
|
+
static {
|
|
194
|
+
__name(this, "KeycloakOAuthProvider");
|
|
195
|
+
}
|
|
196
|
+
config;
|
|
197
|
+
issuer;
|
|
198
|
+
jwks = null;
|
|
199
|
+
constructor(config) {
|
|
200
|
+
this.config = config;
|
|
201
|
+
const serverUrl = config.serverUrl.replace(/\/$/, "");
|
|
202
|
+
this.issuer = `${serverUrl}/realms/${config.realm}`;
|
|
203
|
+
}
|
|
204
|
+
getJWKS() {
|
|
205
|
+
if (!this.jwks) {
|
|
206
|
+
this.jwks = createRemoteJWKSet3(
|
|
207
|
+
new URL(`${this.issuer}/protocol/openid-connect/certs`)
|
|
208
|
+
);
|
|
209
|
+
}
|
|
210
|
+
return this.jwks;
|
|
211
|
+
}
|
|
212
|
+
async verifyToken(token) {
|
|
213
|
+
if (this.config.verifyJwt === false) {
|
|
214
|
+
console.warn("[Keycloak OAuth] \u26A0\uFE0F JWT verification is disabled");
|
|
215
|
+
console.warn(
|
|
216
|
+
"[Keycloak OAuth] Enable verifyJwt: true for production"
|
|
217
|
+
);
|
|
218
|
+
const parts = token.split(".");
|
|
219
|
+
if (parts.length !== 3) {
|
|
220
|
+
throw new Error("Invalid JWT format");
|
|
221
|
+
}
|
|
222
|
+
const payload = JSON.parse(
|
|
223
|
+
Buffer.from(parts[1], "base64url").toString("utf8")
|
|
224
|
+
);
|
|
225
|
+
return { payload };
|
|
226
|
+
}
|
|
227
|
+
try {
|
|
228
|
+
const result = await jwtVerify3(token, this.getJWKS(), {
|
|
229
|
+
issuer: this.issuer,
|
|
230
|
+
// Don't verify audience if not specified
|
|
231
|
+
...this.config.clientId && { audience: this.config.clientId }
|
|
232
|
+
});
|
|
233
|
+
return result;
|
|
234
|
+
} catch (error) {
|
|
235
|
+
throw new Error(`Keycloak JWT verification failed: ${error}`);
|
|
236
|
+
}
|
|
237
|
+
}
|
|
238
|
+
getUserInfo(payload) {
|
|
239
|
+
const realmRoles = payload.realm_access?.roles || [];
|
|
240
|
+
const clientRoles = this.config.clientId && payload.resource_access?.[this.config.clientId]?.roles || [];
|
|
241
|
+
const allRoles = [...realmRoles, ...clientRoles];
|
|
242
|
+
const permissions = [];
|
|
243
|
+
if (payload.resource_access) {
|
|
244
|
+
Object.entries(payload.resource_access).forEach(
|
|
245
|
+
([resource, access]) => {
|
|
246
|
+
if (access.roles) {
|
|
247
|
+
access.roles.forEach((role) => {
|
|
248
|
+
permissions.push(`${resource}:${role}`);
|
|
249
|
+
});
|
|
250
|
+
}
|
|
251
|
+
}
|
|
252
|
+
);
|
|
253
|
+
}
|
|
254
|
+
return {
|
|
255
|
+
userId: payload.sub,
|
|
256
|
+
email: payload.email,
|
|
257
|
+
name: payload.name,
|
|
258
|
+
username: payload.preferred_username,
|
|
259
|
+
nickname: payload.preferred_username,
|
|
260
|
+
picture: payload.picture,
|
|
261
|
+
roles: allRoles,
|
|
262
|
+
permissions,
|
|
263
|
+
// Include scope as well
|
|
264
|
+
scopes: payload.scope ? payload.scope.split(" ") : [],
|
|
265
|
+
// Keycloak-specific claims
|
|
266
|
+
email_verified: payload.email_verified,
|
|
267
|
+
given_name: payload.given_name,
|
|
268
|
+
family_name: payload.family_name,
|
|
269
|
+
realm_access: payload.realm_access,
|
|
270
|
+
resource_access: payload.resource_access
|
|
271
|
+
};
|
|
272
|
+
}
|
|
273
|
+
getIssuer() {
|
|
274
|
+
return this.issuer;
|
|
275
|
+
}
|
|
276
|
+
getAuthEndpoint() {
|
|
277
|
+
return `${this.issuer}/protocol/openid-connect/auth`;
|
|
278
|
+
}
|
|
279
|
+
getTokenEndpoint() {
|
|
280
|
+
return `${this.issuer}/protocol/openid-connect/token`;
|
|
281
|
+
}
|
|
282
|
+
getScopesSupported() {
|
|
283
|
+
return ["openid", "profile", "email", "offline_access", "roles"];
|
|
284
|
+
}
|
|
285
|
+
getGrantTypesSupported() {
|
|
286
|
+
return ["authorization_code", "refresh_token", "client_credentials"];
|
|
287
|
+
}
|
|
288
|
+
};
|
|
289
|
+
|
|
290
|
+
// src/server/oauth/providers/workos.ts
|
|
291
|
+
import { jwtVerify as jwtVerify4, createRemoteJWKSet as createRemoteJWKSet4, decodeJwt as decodeJwt2 } from "jose";
|
|
292
|
+
var WorkOSOAuthProvider = class {
|
|
293
|
+
static {
|
|
294
|
+
__name(this, "WorkOSOAuthProvider");
|
|
295
|
+
}
|
|
296
|
+
config;
|
|
297
|
+
issuer;
|
|
298
|
+
jwks = null;
|
|
299
|
+
constructor(config) {
|
|
300
|
+
this.config = config;
|
|
301
|
+
this.issuer = `https://${config.subdomain}.authkit.app`;
|
|
302
|
+
}
|
|
303
|
+
getJWKS() {
|
|
304
|
+
if (!this.jwks) {
|
|
305
|
+
this.jwks = createRemoteJWKSet4(new URL(`${this.issuer}/oauth2/jwks`));
|
|
306
|
+
}
|
|
307
|
+
return this.jwks;
|
|
308
|
+
}
|
|
309
|
+
async verifyToken(token) {
|
|
310
|
+
if (this.config.verifyJwt === false) {
|
|
311
|
+
console.warn("[WorkOS OAuth] \u26A0\uFE0F JWT verification is disabled");
|
|
312
|
+
console.warn("[WorkOS OAuth] Enable verifyJwt: true for production");
|
|
313
|
+
const parts = token.split(".");
|
|
314
|
+
if (parts.length !== 3) {
|
|
315
|
+
throw new Error("Invalid JWT format");
|
|
316
|
+
}
|
|
317
|
+
const payload = decodeJwt2(token);
|
|
318
|
+
return { payload };
|
|
319
|
+
}
|
|
320
|
+
try {
|
|
321
|
+
const result = await jwtVerify4(token, this.getJWKS(), {
|
|
322
|
+
issuer: this.issuer
|
|
323
|
+
});
|
|
324
|
+
return result;
|
|
325
|
+
} catch (error) {
|
|
326
|
+
throw new Error(`WorkOS JWT verification failed: ${error}`);
|
|
327
|
+
}
|
|
328
|
+
}
|
|
329
|
+
getUserInfo(payload) {
|
|
330
|
+
return {
|
|
331
|
+
userId: payload.sub,
|
|
332
|
+
email: payload.email,
|
|
333
|
+
name: payload.name,
|
|
334
|
+
username: payload.preferred_username,
|
|
335
|
+
picture: payload.picture,
|
|
336
|
+
// WorkOS includes permissions and roles in token
|
|
337
|
+
permissions: payload.permissions || [],
|
|
338
|
+
roles: payload.roles || [],
|
|
339
|
+
// Include scope as well
|
|
340
|
+
scopes: payload.scope ? payload.scope.split(" ") : [],
|
|
341
|
+
// Additional WorkOS-specific claims
|
|
342
|
+
email_verified: payload.email_verified,
|
|
343
|
+
organization_id: payload.org_id,
|
|
344
|
+
sid: payload.sid
|
|
345
|
+
// Session ID
|
|
346
|
+
};
|
|
347
|
+
}
|
|
348
|
+
getIssuer() {
|
|
349
|
+
return this.issuer;
|
|
350
|
+
}
|
|
351
|
+
getAuthEndpoint() {
|
|
352
|
+
return `${this.issuer}/oauth2/authorize`;
|
|
353
|
+
}
|
|
354
|
+
getTokenEndpoint() {
|
|
355
|
+
return `${this.issuer}/oauth2/token`;
|
|
356
|
+
}
|
|
357
|
+
getScopesSupported() {
|
|
358
|
+
return ["email", "offline_access", "openid", "profile"];
|
|
359
|
+
}
|
|
360
|
+
getGrantTypesSupported() {
|
|
361
|
+
return ["authorization_code", "refresh_token"];
|
|
362
|
+
}
|
|
363
|
+
getMode() {
|
|
364
|
+
if (this.config.clientId) {
|
|
365
|
+
console.log("[WorkOS OAuth] Using proxy mode (pre-registered client)");
|
|
366
|
+
return "proxy";
|
|
367
|
+
}
|
|
368
|
+
console.log(
|
|
369
|
+
"[WorkOS OAuth] Using direct mode (Dynamic Client Registration)"
|
|
370
|
+
);
|
|
371
|
+
return "direct";
|
|
372
|
+
}
|
|
373
|
+
getRegistrationEndpoint() {
|
|
374
|
+
if (this.config.clientId) {
|
|
375
|
+
return void 0;
|
|
376
|
+
}
|
|
377
|
+
return `${this.issuer}/oauth2/register`;
|
|
378
|
+
}
|
|
379
|
+
};
|
|
380
|
+
|
|
381
|
+
// src/server/oauth/providers/custom.ts
|
|
382
|
+
var CustomOAuthProvider = class {
|
|
383
|
+
static {
|
|
384
|
+
__name(this, "CustomOAuthProvider");
|
|
385
|
+
}
|
|
386
|
+
config;
|
|
387
|
+
constructor(config) {
|
|
388
|
+
this.config = config;
|
|
389
|
+
}
|
|
390
|
+
async verifyToken(token) {
|
|
391
|
+
try {
|
|
392
|
+
const result = await this.config.verifyToken(token);
|
|
393
|
+
return { payload: result };
|
|
394
|
+
} catch (error) {
|
|
395
|
+
throw new Error(`Custom OAuth verification failed: ${error}`);
|
|
396
|
+
}
|
|
397
|
+
}
|
|
398
|
+
getUserInfo(payload) {
|
|
399
|
+
if (this.config.getUserInfo) {
|
|
400
|
+
return this.config.getUserInfo(payload);
|
|
401
|
+
}
|
|
402
|
+
return {
|
|
403
|
+
userId: payload.sub || payload.user_id || payload.id,
|
|
404
|
+
email: payload.email,
|
|
405
|
+
name: payload.name,
|
|
406
|
+
username: payload.username || payload.preferred_username,
|
|
407
|
+
nickname: payload.nickname,
|
|
408
|
+
picture: payload.picture || payload.avatar_url,
|
|
409
|
+
roles: payload.roles || [],
|
|
410
|
+
permissions: payload.permissions || [],
|
|
411
|
+
scopes: payload.scope ? payload.scope.split(" ") : []
|
|
412
|
+
};
|
|
413
|
+
}
|
|
414
|
+
getIssuer() {
|
|
415
|
+
return this.config.issuer;
|
|
416
|
+
}
|
|
417
|
+
getAuthEndpoint() {
|
|
418
|
+
return this.config.authEndpoint;
|
|
419
|
+
}
|
|
420
|
+
getTokenEndpoint() {
|
|
421
|
+
return this.config.tokenEndpoint;
|
|
422
|
+
}
|
|
423
|
+
getScopesSupported() {
|
|
424
|
+
return this.config.scopesSupported || ["openid", "profile", "email"];
|
|
425
|
+
}
|
|
426
|
+
getGrantTypesSupported() {
|
|
427
|
+
return this.config.grantTypesSupported || ["authorization_code", "refresh_token"];
|
|
428
|
+
}
|
|
429
|
+
};
|
|
430
|
+
|
|
431
|
+
// src/server/oauth/providers.ts
|
|
432
|
+
function oauthSupabaseProvider(config = {}) {
|
|
433
|
+
const projectId = config.projectId ?? getEnv("MCP_USE_OAUTH_SUPABASE_PROJECT_ID");
|
|
434
|
+
const jwtSecret = config.jwtSecret ?? getEnv("MCP_USE_OAUTH_SUPABASE_JWT_SECRET");
|
|
435
|
+
if (!projectId) {
|
|
436
|
+
throw new Error(
|
|
437
|
+
"Supabase projectId is required. Set MCP_USE_OAUTH_SUPABASE_PROJECT_ID environment variable or pass projectId in config."
|
|
438
|
+
);
|
|
439
|
+
}
|
|
440
|
+
return new SupabaseOAuthProvider({
|
|
441
|
+
provider: "supabase",
|
|
442
|
+
projectId,
|
|
443
|
+
jwtSecret,
|
|
444
|
+
skipVerification: config.skipVerification
|
|
445
|
+
});
|
|
446
|
+
}
|
|
447
|
+
__name(oauthSupabaseProvider, "oauthSupabaseProvider");
|
|
448
|
+
function oauthAuth0Provider(config = {}) {
|
|
449
|
+
const domain = config.domain ?? getEnv("MCP_USE_OAUTH_AUTH0_DOMAIN");
|
|
450
|
+
const audience = config.audience ?? getEnv("MCP_USE_OAUTH_AUTH0_AUDIENCE");
|
|
451
|
+
if (!domain) {
|
|
452
|
+
throw new Error(
|
|
453
|
+
"Auth0 domain is required. Set MCP_USE_OAUTH_AUTH0_DOMAIN environment variable or pass domain in config."
|
|
454
|
+
);
|
|
455
|
+
}
|
|
456
|
+
if (!audience) {
|
|
457
|
+
throw new Error(
|
|
458
|
+
"Auth0 audience is required. Set MCP_USE_OAUTH_AUTH0_AUDIENCE environment variable or pass audience in config."
|
|
459
|
+
);
|
|
460
|
+
}
|
|
461
|
+
return new Auth0OAuthProvider({
|
|
462
|
+
provider: "auth0",
|
|
463
|
+
domain,
|
|
464
|
+
audience,
|
|
465
|
+
verifyJwt: config.verifyJwt
|
|
466
|
+
});
|
|
467
|
+
}
|
|
468
|
+
__name(oauthAuth0Provider, "oauthAuth0Provider");
|
|
469
|
+
function oauthKeycloakProvider(config = {}) {
|
|
470
|
+
const serverUrl = config.serverUrl ?? getEnv("MCP_USE_OAUTH_KEYCLOAK_SERVER_URL");
|
|
471
|
+
const realm = config.realm ?? getEnv("MCP_USE_OAUTH_KEYCLOAK_REALM");
|
|
472
|
+
const clientId = config.clientId ?? getEnv("MCP_USE_OAUTH_KEYCLOAK_CLIENT_ID");
|
|
473
|
+
if (!serverUrl) {
|
|
474
|
+
throw new Error(
|
|
475
|
+
"Keycloak serverUrl is required. Set MCP_USE_OAUTH_KEYCLOAK_SERVER_URL environment variable or pass serverUrl in config."
|
|
476
|
+
);
|
|
477
|
+
}
|
|
478
|
+
if (!realm) {
|
|
479
|
+
throw new Error(
|
|
480
|
+
"Keycloak realm is required. Set MCP_USE_OAUTH_KEYCLOAK_REALM environment variable or pass realm in config."
|
|
481
|
+
);
|
|
482
|
+
}
|
|
483
|
+
return new KeycloakOAuthProvider({
|
|
484
|
+
provider: "keycloak",
|
|
485
|
+
serverUrl,
|
|
486
|
+
realm,
|
|
487
|
+
clientId,
|
|
488
|
+
verifyJwt: config.verifyJwt
|
|
489
|
+
});
|
|
490
|
+
}
|
|
491
|
+
__name(oauthKeycloakProvider, "oauthKeycloakProvider");
|
|
492
|
+
function oauthWorkOSProvider(config = {}) {
|
|
493
|
+
const subdomain = config.subdomain ?? getEnv("MCP_USE_OAUTH_WORKOS_SUBDOMAIN");
|
|
494
|
+
const clientId = config.clientId ?? getEnv("MCP_USE_OAUTH_WORKOS_CLIENT_ID");
|
|
495
|
+
const apiKey = config.apiKey ?? getEnv("MCP_USE_OAUTH_WORKOS_API_KEY");
|
|
496
|
+
if (!subdomain) {
|
|
497
|
+
throw new Error(
|
|
498
|
+
"WorkOS subdomain is required. Set MCP_USE_OAUTH_WORKOS_SUBDOMAIN environment variable or pass subdomain in config."
|
|
499
|
+
);
|
|
500
|
+
}
|
|
501
|
+
if (clientId) {
|
|
502
|
+
console.log("[WorkOS OAuth] Using pre-registered OAuth client mode");
|
|
503
|
+
console.log(`[WorkOS OAuth] - Client ID: ${clientId}`);
|
|
504
|
+
console.log(
|
|
505
|
+
"[WorkOS OAuth] - Make sure this client exists in WorkOS Dashboard"
|
|
506
|
+
);
|
|
507
|
+
console.log(
|
|
508
|
+
"[WorkOS OAuth] - Configure redirect URIs to match your MCP client"
|
|
509
|
+
);
|
|
510
|
+
} else {
|
|
511
|
+
console.log("[WorkOS OAuth] Using Dynamic Client Registration (DCR) mode");
|
|
512
|
+
console.log(
|
|
513
|
+
"[WorkOS OAuth] - MCP clients will register themselves automatically"
|
|
514
|
+
);
|
|
515
|
+
console.log(
|
|
516
|
+
"[WorkOS OAuth] - Make sure DCR is enabled in WorkOS Dashboard"
|
|
517
|
+
);
|
|
518
|
+
}
|
|
519
|
+
return new WorkOSOAuthProvider({
|
|
520
|
+
provider: "workos",
|
|
521
|
+
subdomain,
|
|
522
|
+
clientId,
|
|
523
|
+
apiKey,
|
|
524
|
+
verifyJwt: config.verifyJwt
|
|
525
|
+
});
|
|
526
|
+
}
|
|
527
|
+
__name(oauthWorkOSProvider, "oauthWorkOSProvider");
|
|
528
|
+
function oauthCustomProvider(config) {
|
|
529
|
+
return new CustomOAuthProvider({
|
|
530
|
+
provider: "custom",
|
|
531
|
+
...config
|
|
532
|
+
});
|
|
533
|
+
}
|
|
534
|
+
__name(oauthCustomProvider, "oauthCustomProvider");
|
|
535
|
+
|
|
536
|
+
// src/server/oauth/middleware.ts
|
|
537
|
+
function createBearerAuthMiddleware(provider, baseUrl) {
|
|
538
|
+
return async (c, next) => {
|
|
539
|
+
const authHeader = c.req.header("Authorization");
|
|
540
|
+
const getWWWAuthenticateHeader = /* @__PURE__ */ __name(() => {
|
|
541
|
+
const base = baseUrl || new URL(c.req.url).origin;
|
|
542
|
+
const parts = [
|
|
543
|
+
'Bearer error="unauthorized"',
|
|
544
|
+
'error_description="Authorization needed"'
|
|
545
|
+
];
|
|
546
|
+
parts.push(
|
|
547
|
+
`resource_metadata="${base}/.well-known/oauth-protected-resource"`
|
|
548
|
+
);
|
|
549
|
+
return parts.join(", ");
|
|
550
|
+
}, "getWWWAuthenticateHeader");
|
|
551
|
+
if (!authHeader) {
|
|
552
|
+
c.header("WWW-Authenticate", getWWWAuthenticateHeader());
|
|
553
|
+
return c.json({ error: "Missing Authorization header" }, 401);
|
|
554
|
+
}
|
|
555
|
+
const [type, token] = authHeader.split(" ");
|
|
556
|
+
if (type.toLowerCase() !== "bearer" || !token) {
|
|
557
|
+
c.header("WWW-Authenticate", getWWWAuthenticateHeader());
|
|
558
|
+
return c.json(
|
|
559
|
+
{
|
|
560
|
+
error: 'Invalid Authorization header format, expected "Bearer TOKEN"'
|
|
561
|
+
},
|
|
562
|
+
401
|
|
563
|
+
);
|
|
564
|
+
}
|
|
565
|
+
try {
|
|
566
|
+
const result = await provider.verifyToken(token);
|
|
567
|
+
const payload = result.payload;
|
|
568
|
+
const user = provider.getUserInfo(payload);
|
|
569
|
+
const authInfo = {
|
|
570
|
+
user,
|
|
571
|
+
payload,
|
|
572
|
+
accessToken: token,
|
|
573
|
+
// Extract scopes from scope claim (OAuth standard)
|
|
574
|
+
scopes: payload.scope ? payload.scope.split(" ") : [],
|
|
575
|
+
// Extract permissions (Auth0 style, or custom)
|
|
576
|
+
permissions: payload.permissions || []
|
|
577
|
+
};
|
|
578
|
+
c.set("auth", authInfo);
|
|
579
|
+
c.auth = authInfo;
|
|
580
|
+
c.set("user", user);
|
|
581
|
+
c.set("payload", payload);
|
|
582
|
+
c.set("accessToken", token);
|
|
583
|
+
await next();
|
|
584
|
+
} catch (error) {
|
|
585
|
+
c.header("WWW-Authenticate", getWWWAuthenticateHeader());
|
|
586
|
+
return c.json({ error: `Invalid token: ${error}` }, 401);
|
|
587
|
+
}
|
|
588
|
+
};
|
|
589
|
+
}
|
|
590
|
+
__name(createBearerAuthMiddleware, "createBearerAuthMiddleware");
|
|
591
|
+
|
|
592
|
+
// src/server/oauth/routes.ts
|
|
593
|
+
import { cors } from "hono/cors";
|
|
594
|
+
function setupOAuthRoutes(app, provider, baseUrl) {
|
|
595
|
+
const mode = provider.getMode?.() || "proxy";
|
|
596
|
+
app.use(
|
|
597
|
+
"/.well-known/*",
|
|
598
|
+
cors({
|
|
599
|
+
origin: "*",
|
|
600
|
+
// Allow all origins for metadata discovery
|
|
601
|
+
allowMethods: ["GET", "OPTIONS"],
|
|
602
|
+
allowHeaders: ["Content-Type", "Authorization"],
|
|
603
|
+
exposeHeaders: ["Content-Type"],
|
|
604
|
+
maxAge: 86400
|
|
605
|
+
// Cache preflight for 24 hours
|
|
606
|
+
})
|
|
607
|
+
);
|
|
608
|
+
if (mode === "proxy") {
|
|
609
|
+
app.use(
|
|
610
|
+
"/authorize",
|
|
611
|
+
cors({
|
|
612
|
+
origin: "*",
|
|
613
|
+
allowMethods: ["GET", "POST", "OPTIONS"],
|
|
614
|
+
allowHeaders: ["Content-Type", "Authorization"],
|
|
615
|
+
maxAge: 86400
|
|
616
|
+
})
|
|
617
|
+
);
|
|
618
|
+
app.use(
|
|
619
|
+
"/token",
|
|
620
|
+
cors({
|
|
621
|
+
origin: "*",
|
|
622
|
+
allowMethods: ["POST", "OPTIONS"],
|
|
623
|
+
allowHeaders: ["Content-Type", "Authorization"],
|
|
624
|
+
maxAge: 86400
|
|
625
|
+
})
|
|
626
|
+
);
|
|
627
|
+
}
|
|
628
|
+
if (mode === "proxy") {
|
|
629
|
+
const handleAuthorize = /* @__PURE__ */ __name(async (c) => {
|
|
630
|
+
const params = c.req.method === "POST" ? await c.req.parseBody() : c.req.query();
|
|
631
|
+
const clientId = params.client_id;
|
|
632
|
+
const redirectUri = params.redirect_uri;
|
|
633
|
+
const responseType = params.response_type;
|
|
634
|
+
const codeChallenge = params.code_challenge;
|
|
635
|
+
const codeChallengeMethod = params.code_challenge_method;
|
|
636
|
+
const state = params.state;
|
|
637
|
+
const scope = params.scope;
|
|
638
|
+
const audience = params.audience;
|
|
639
|
+
if (!clientId || !redirectUri || !responseType || !codeChallenge) {
|
|
640
|
+
return c.json(
|
|
641
|
+
{
|
|
642
|
+
error: "invalid_request",
|
|
643
|
+
error_description: "Missing required parameters"
|
|
644
|
+
},
|
|
645
|
+
400
|
|
646
|
+
);
|
|
647
|
+
}
|
|
648
|
+
const authUrl = new URL(provider.getAuthEndpoint());
|
|
649
|
+
authUrl.searchParams.set("client_id", clientId);
|
|
650
|
+
authUrl.searchParams.set("redirect_uri", redirectUri);
|
|
651
|
+
authUrl.searchParams.set("response_type", responseType);
|
|
652
|
+
authUrl.searchParams.set("code_challenge", codeChallenge);
|
|
653
|
+
authUrl.searchParams.set(
|
|
654
|
+
"code_challenge_method",
|
|
655
|
+
codeChallengeMethod || "S256"
|
|
656
|
+
);
|
|
657
|
+
if (state) authUrl.searchParams.set("state", state);
|
|
658
|
+
if (scope) authUrl.searchParams.set("scope", scope);
|
|
659
|
+
if (audience) authUrl.searchParams.set("audience", audience);
|
|
660
|
+
return c.redirect(authUrl.toString(), 302);
|
|
661
|
+
}, "handleAuthorize");
|
|
662
|
+
app.get("/authorize", handleAuthorize);
|
|
663
|
+
app.post("/authorize", handleAuthorize);
|
|
664
|
+
app.post("/token", async (c) => {
|
|
665
|
+
try {
|
|
666
|
+
const body = await c.req.parseBody();
|
|
667
|
+
const response = await fetch(provider.getTokenEndpoint(), {
|
|
668
|
+
method: "POST",
|
|
669
|
+
headers: {
|
|
670
|
+
"Content-Type": "application/x-www-form-urlencoded"
|
|
671
|
+
},
|
|
672
|
+
body: new URLSearchParams(body).toString()
|
|
673
|
+
});
|
|
674
|
+
const data = await response.json();
|
|
675
|
+
if (!response.ok) {
|
|
676
|
+
return c.json(data, response.status);
|
|
677
|
+
}
|
|
678
|
+
return c.json(data);
|
|
679
|
+
} catch (error) {
|
|
680
|
+
return c.json(
|
|
681
|
+
{
|
|
682
|
+
error: "server_error",
|
|
683
|
+
error_description: `Token exchange failed: ${error}`
|
|
684
|
+
},
|
|
685
|
+
500
|
|
686
|
+
);
|
|
687
|
+
}
|
|
688
|
+
});
|
|
689
|
+
}
|
|
690
|
+
const handleAuthorizationServerMetadata = /* @__PURE__ */ __name(async (c) => {
|
|
691
|
+
const requestPath = new URL(c.req.url).pathname;
|
|
692
|
+
console.log(`[OAuth] Metadata request: ${requestPath} (mode: ${mode})`);
|
|
693
|
+
if (mode === "direct") {
|
|
694
|
+
try {
|
|
695
|
+
const metadataUrl = `${provider.getIssuer()}/.well-known/oauth-authorization-server`;
|
|
696
|
+
console.log(`[OAuth] Fetching metadata from provider: ${metadataUrl}`);
|
|
697
|
+
const response = await fetch(metadataUrl);
|
|
698
|
+
if (!response.ok) {
|
|
699
|
+
console.error(
|
|
700
|
+
`[OAuth] Failed to fetch provider metadata: ${response.status}`
|
|
701
|
+
);
|
|
702
|
+
return c.json(
|
|
703
|
+
{
|
|
704
|
+
error: "server_error",
|
|
705
|
+
error_description: `Failed to fetch provider metadata: ${response.status}`
|
|
706
|
+
},
|
|
707
|
+
500
|
|
708
|
+
);
|
|
709
|
+
}
|
|
710
|
+
const metadata = await response.json();
|
|
711
|
+
const hasRegisteredClient = provider.getRegistrationEndpoint && provider.config?.clientId;
|
|
712
|
+
if (hasRegisteredClient) {
|
|
713
|
+
console.log(
|
|
714
|
+
`[OAuth] Provider has pre-registered client - removing DCR endpoint`
|
|
715
|
+
);
|
|
716
|
+
delete metadata.registration_endpoint;
|
|
717
|
+
}
|
|
718
|
+
console.log(`[OAuth] Provider metadata retrieved successfully`);
|
|
719
|
+
console.log(`[OAuth] - Issuer: ${metadata.issuer}`);
|
|
720
|
+
console.log(
|
|
721
|
+
`[OAuth] - Registration endpoint: ${metadata.registration_endpoint || "not available (using pre-registered client)"}`
|
|
722
|
+
);
|
|
723
|
+
return c.json(metadata);
|
|
724
|
+
} catch (error) {
|
|
725
|
+
console.error(`[OAuth] Error fetching provider metadata:`, error);
|
|
726
|
+
return c.json(
|
|
727
|
+
{
|
|
728
|
+
error: "server_error",
|
|
729
|
+
error_description: `Failed to fetch provider metadata: ${error}`
|
|
730
|
+
},
|
|
731
|
+
500
|
|
732
|
+
);
|
|
733
|
+
}
|
|
734
|
+
} else {
|
|
735
|
+
console.log(`[OAuth] Returning proxy mode metadata`);
|
|
736
|
+
return c.json({
|
|
737
|
+
issuer: provider.getIssuer(),
|
|
738
|
+
authorization_endpoint: `${baseUrl}/authorize`,
|
|
739
|
+
token_endpoint: `${baseUrl}/token`,
|
|
740
|
+
response_types_supported: ["code"],
|
|
741
|
+
grant_types_supported: provider.getGrantTypesSupported(),
|
|
742
|
+
code_challenge_methods_supported: ["S256"],
|
|
743
|
+
token_endpoint_auth_methods_supported: [
|
|
744
|
+
"client_secret_post",
|
|
745
|
+
"client_secret_basic",
|
|
746
|
+
"none"
|
|
747
|
+
],
|
|
748
|
+
scopes_supported: provider.getScopesSupported()
|
|
749
|
+
});
|
|
750
|
+
}
|
|
751
|
+
}, "handleAuthorizationServerMetadata");
|
|
752
|
+
app.get(
|
|
753
|
+
"/.well-known/oauth-authorization-server",
|
|
754
|
+
handleAuthorizationServerMetadata
|
|
755
|
+
);
|
|
756
|
+
app.get(
|
|
757
|
+
"/.well-known/openid-configuration",
|
|
758
|
+
handleAuthorizationServerMetadata
|
|
759
|
+
);
|
|
760
|
+
app.get("/.well-known/oauth-protected-resource", (c) => {
|
|
761
|
+
console.log(`[OAuth] Protected resource metadata request (mode: ${mode})`);
|
|
762
|
+
console.log(`[OAuth] - Resource: ${baseUrl}`);
|
|
763
|
+
console.log(`[OAuth] - Authorization server: ${provider.getIssuer()}`);
|
|
764
|
+
return c.json({
|
|
765
|
+
resource: baseUrl,
|
|
766
|
+
authorization_servers: [provider.getIssuer()],
|
|
767
|
+
bearer_methods_supported: ["header"],
|
|
768
|
+
resource_documentation: mode === "direct" ? "This resource uses direct OAuth flow. Clients communicate directly with the authorization server." : void 0
|
|
769
|
+
});
|
|
770
|
+
});
|
|
771
|
+
app.get("/.well-known/oauth-protected-resource/mcp", (c) => {
|
|
772
|
+
return c.json({
|
|
773
|
+
resource: `${baseUrl}/mcp`,
|
|
774
|
+
authorization_servers: [provider.getIssuer()],
|
|
775
|
+
bearer_methods_supported: ["header"]
|
|
776
|
+
});
|
|
777
|
+
});
|
|
778
|
+
}
|
|
779
|
+
__name(setupOAuthRoutes, "setupOAuthRoutes");
|
|
780
|
+
|
|
781
|
+
// src/server/oauth/utils.ts
|
|
782
|
+
function getAuth(context) {
|
|
783
|
+
return context.get("auth");
|
|
784
|
+
}
|
|
785
|
+
__name(getAuth, "getAuth");
|
|
786
|
+
function hasScope(context, needed) {
|
|
787
|
+
const { scopes, permissions } = getAuth(context);
|
|
788
|
+
const requiredScopes = Array.isArray(needed) ? needed : [needed];
|
|
789
|
+
return requiredScopes.every(
|
|
790
|
+
(scope) => scopes.includes(scope) || permissions.includes(scope)
|
|
791
|
+
);
|
|
792
|
+
}
|
|
793
|
+
__name(hasScope, "hasScope");
|
|
794
|
+
function hasAnyScope(context, needed) {
|
|
795
|
+
const { scopes, permissions } = getAuth(context);
|
|
796
|
+
return needed.some(
|
|
797
|
+
(scope) => scopes.includes(scope) || permissions.includes(scope)
|
|
798
|
+
);
|
|
799
|
+
}
|
|
800
|
+
__name(hasAnyScope, "hasAnyScope");
|
|
801
|
+
function requireScope(needed) {
|
|
802
|
+
return async (c, next) => {
|
|
803
|
+
if (!hasScope(c, needed)) {
|
|
804
|
+
const { scopes, permissions } = getAuth(c);
|
|
805
|
+
const requiredScopes = Array.isArray(needed) ? needed : [needed];
|
|
806
|
+
return c.json(
|
|
807
|
+
{
|
|
808
|
+
error: "insufficient_scope",
|
|
809
|
+
required: requiredScopes,
|
|
810
|
+
granted_scopes: scopes,
|
|
811
|
+
granted_permissions: permissions,
|
|
812
|
+
message: `Missing required scope(s): ${requiredScopes.join(", ")}`
|
|
813
|
+
},
|
|
814
|
+
403
|
|
815
|
+
);
|
|
816
|
+
}
|
|
817
|
+
await next();
|
|
818
|
+
};
|
|
819
|
+
}
|
|
820
|
+
__name(requireScope, "requireScope");
|
|
821
|
+
function requireAnyScope(needed) {
|
|
822
|
+
return async (c, next) => {
|
|
823
|
+
if (!hasAnyScope(c, needed)) {
|
|
824
|
+
const { scopes, permissions } = getAuth(c);
|
|
825
|
+
return c.json(
|
|
826
|
+
{
|
|
827
|
+
error: "insufficient_scope",
|
|
828
|
+
required_any: needed,
|
|
829
|
+
granted_scopes: scopes,
|
|
830
|
+
granted_permissions: permissions,
|
|
831
|
+
message: `Missing at least one required scope from: ${needed.join(", ")}`
|
|
832
|
+
},
|
|
833
|
+
403
|
|
834
|
+
);
|
|
835
|
+
}
|
|
836
|
+
await next();
|
|
837
|
+
};
|
|
838
|
+
}
|
|
839
|
+
__name(requireAnyScope, "requireAnyScope");
|
|
840
|
+
|
|
841
|
+
export {
|
|
842
|
+
oauthSupabaseProvider,
|
|
843
|
+
oauthAuth0Provider,
|
|
844
|
+
oauthKeycloakProvider,
|
|
845
|
+
oauthWorkOSProvider,
|
|
846
|
+
oauthCustomProvider,
|
|
847
|
+
createBearerAuthMiddleware,
|
|
848
|
+
setupOAuthRoutes,
|
|
849
|
+
getAuth,
|
|
850
|
+
hasScope,
|
|
851
|
+
hasAnyScope,
|
|
852
|
+
requireScope,
|
|
853
|
+
requireAnyScope
|
|
854
|
+
};
|