@q32/core 0.1.14 → 0.1.16

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/oauth.d.ts CHANGED
@@ -1,4 +1,5 @@
1
1
  import type { FetchLike } from "./http.js";
2
+ import type { D1DatabaseLike } from "./d1.js";
2
3
  export type OAuthMetadataOptions = {
3
4
  issuer: string;
4
5
  authorizationPath?: string;
@@ -42,6 +43,79 @@ export type GitHubUserProfile = {
42
43
  name: string | null;
43
44
  avatar_url: string | null;
44
45
  };
46
+ export type OAuthClientInformation = {
47
+ client_id: string;
48
+ client_secret?: string;
49
+ client_name?: string;
50
+ redirect_uris?: string[];
51
+ scope?: string;
52
+ grant_types?: string[];
53
+ response_types?: string[];
54
+ token_endpoint_auth_method?: string;
55
+ client_uri?: string;
56
+ logo_uri?: string;
57
+ contacts?: string[];
58
+ tos_uri?: string;
59
+ policy_uri?: string;
60
+ software_id?: string;
61
+ software_version?: string;
62
+ client_id_issued_at?: number;
63
+ client_secret_expires_at?: number;
64
+ };
65
+ export type OAuthClientRegistration = Omit<OAuthClientInformation, "client_id" | "client_id_issued_at">;
66
+ export type OAuthTokens = {
67
+ access_token: string;
68
+ token_type: "Bearer";
69
+ expires_in: number;
70
+ refresh_token?: string;
71
+ scope?: string;
72
+ };
73
+ export type McpOAuthSubjectColumn = {
74
+ field: string;
75
+ column: string;
76
+ };
77
+ export type McpOAuthRepositoryOptions = {
78
+ defaultScope?: string;
79
+ tokenEndpointAuthMethod?: string;
80
+ subjectColumns?: McpOAuthSubjectColumn[];
81
+ refreshRotationColumns?: boolean;
82
+ };
83
+ export type McpAuthorizationCodeRow = {
84
+ authorizationCodeId: string;
85
+ clientId: string;
86
+ redirectUri: string;
87
+ scopesJson: string;
88
+ resource: string | null;
89
+ codeChallenge: string;
90
+ expiresAt: number;
91
+ usedAt: string | null;
92
+ subject: Record<string, string>;
93
+ };
94
+ export type McpTokenRow = {
95
+ tokenId: string;
96
+ clientId: string;
97
+ scopesJson: string;
98
+ resource: string | null;
99
+ accessExpiresAt: number;
100
+ refreshExpiresAt: number | null;
101
+ revokedAt: string | null;
102
+ subject: Record<string, string>;
103
+ rotatedToTokenId?: string | null;
104
+ refreshReuseExpiresAt?: number | null;
105
+ rotatedResponseCiphertext?: string | null;
106
+ rotatedResponseNonce?: string | null;
107
+ };
108
+ export type McpIssuedTokenSet = {
109
+ tokenId: string;
110
+ tokens: OAuthTokens;
111
+ accessExpiresAt: number;
112
+ refreshExpiresAt: number | null;
113
+ };
114
+ export type McpOAuthTokenOptions = {
115
+ accessTokenTtlSeconds?: number;
116
+ refreshTokenTtlSeconds?: number;
117
+ now?: () => number;
118
+ };
45
119
  export declare class GoogleOAuthClient {
46
120
  private readonly fetchImpl;
47
121
  constructor(fetchImpl?: FetchLike);
@@ -67,4 +141,60 @@ export declare class GitHubOAuthClient {
67
141
  fetchPrimaryEmail(accessToken: string): Promise<string | null>;
68
142
  private githubHeaders;
69
143
  }
144
+ export declare class McpOAuthRepository {
145
+ private readonly db;
146
+ private readonly options;
147
+ constructor(db: D1DatabaseLike, options?: McpOAuthRepositoryOptions);
148
+ getClient(clientId: string): Promise<OAuthClientInformation | undefined>;
149
+ registerClient(client: OAuthClientRegistration): Promise<OAuthClientInformation>;
150
+ createAuthorizationCode(input: {
151
+ code: string;
152
+ clientId: string;
153
+ subject: Record<string, string>;
154
+ redirectUri: string;
155
+ scopes: string[];
156
+ resource: string | null;
157
+ codeChallenge: string;
158
+ expiresAt?: number;
159
+ }): Promise<void>;
160
+ getAuthorizationCode(code: string): Promise<McpAuthorizationCodeRow | null>;
161
+ consumeAuthorizationCode(authorizationCodeId: string): Promise<void>;
162
+ createTokenSet(input: {
163
+ clientId: string;
164
+ subject: Record<string, string>;
165
+ accessToken: string;
166
+ refreshToken: string | null;
167
+ scopes: string[];
168
+ resource: string | null;
169
+ accessExpiresAt: number;
170
+ refreshExpiresAt: number | null;
171
+ }): Promise<string>;
172
+ getTokenByAccessToken(token: string): Promise<McpTokenRow | null>;
173
+ getTokenByRefreshToken(token: string): Promise<McpTokenRow | null>;
174
+ revokeToken(tokenId: string): Promise<void>;
175
+ touchAccessToken(tokenId: string): Promise<void>;
176
+ markTokenRotated(input: {
177
+ tokenId: string;
178
+ rotatedToTokenId: string;
179
+ refreshReuseExpiresAt: number;
180
+ rotatedResponseCiphertext: string;
181
+ rotatedResponseNonce: string;
182
+ }): Promise<boolean>;
183
+ private getTokenByHashColumn;
184
+ private subjectSelectSql;
185
+ }
186
+ export declare function issueMcpOAuthTokenSet(repository: McpOAuthRepository, input: {
187
+ clientId: string;
188
+ subject: Record<string, string>;
189
+ scopes: string[];
190
+ resource?: URL | null;
191
+ }, options?: McpOAuthTokenOptions): Promise<McpIssuedTokenSet>;
192
+ export declare function parseOAuthScope(scope: string | null | undefined): string[];
193
+ export declare function parseOAuthJsonArray(value: string | null | undefined): string[];
194
+ export declare function createOAuthRedirect(redirectUri: string, params: Record<string, string | undefined>): string;
195
+ export declare function encryptOAuthTokenResponse(tokens: OAuthTokens, secret: string): Promise<{
196
+ ciphertext: string;
197
+ nonce: string;
198
+ }>;
199
+ export declare function decryptOAuthTokenResponse(ciphertext: string, nonce: string, secret: string): Promise<OAuthTokens | null>;
70
200
  //# sourceMappingURL=oauth.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"oauth.d.ts","sourceRoot":"","sources":["../src/oauth.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"oauth.d.ts","sourceRoot":"","sources":["../src/oauth.ts"],"names":[],"mappings":"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"}
package/dist/oauth.js CHANGED
@@ -1,4 +1,6 @@
1
1
  import { defaultFetch } from "./http.js";
2
+ import { sha256Hex } from "./hash.js";
3
+ import { createId, createToken, fromBase64Url, toBase64Url } from "./ids.js";
2
4
  export function oauthAuthorizationServerMetadata(options) {
3
5
  const issuer = options.issuer.replace(/\/$/, "");
4
6
  return {
@@ -31,6 +33,10 @@ export function mcpServerCard(options) {
31
33
  transport: "http",
32
34
  };
33
35
  }
36
+ const DEFAULT_MCP_SUBJECT_COLUMNS = [{ field: "accountId", column: "account_id" }];
37
+ const DEFAULT_AUTH_CODE_TTL_SECONDS = 10 * 60;
38
+ const DEFAULT_ACCESS_TOKEN_TTL_SECONDS = 60 * 60;
39
+ const DEFAULT_REFRESH_TOKEN_TTL_SECONDS = 30 * 24 * 60 * 60;
34
40
  export class GoogleOAuthClient {
35
41
  fetchImpl;
36
42
  constructor(fetchImpl = defaultFetch) {
@@ -81,7 +87,7 @@ export class GoogleOAuthClient {
81
87
  if (!profile.sub || !profile.email)
82
88
  throw new Error("Google profile missing identity fields");
83
89
  if (options.requireVerifiedEmail && profile.email_verified === false)
84
- throw new Error("Google profile email is not verified");
90
+ throw new Error("Google profile missing verified identity fields");
85
91
  return profile;
86
92
  }
87
93
  }
@@ -148,10 +154,398 @@ export class GitHubOAuthClient {
148
154
  };
149
155
  }
150
156
  }
157
+ export class McpOAuthRepository {
158
+ db;
159
+ options;
160
+ constructor(db, options = {}) {
161
+ this.db = db;
162
+ this.options = {
163
+ defaultScope: options.defaultScope ?? "mcp:read",
164
+ tokenEndpointAuthMethod: options.tokenEndpointAuthMethod ?? "none",
165
+ subjectColumns: options.subjectColumns ?? DEFAULT_MCP_SUBJECT_COLUMNS,
166
+ refreshRotationColumns: options.refreshRotationColumns ?? false,
167
+ };
168
+ }
169
+ async getClient(clientId) {
170
+ const row = await this.db
171
+ .prepare(`
172
+ SELECT
173
+ client_id AS clientId,
174
+ client_secret AS clientSecret,
175
+ client_name AS clientName,
176
+ redirect_uris_json AS redirectUrisJson,
177
+ scope,
178
+ grant_types_json AS grantTypesJson,
179
+ response_types_json AS responseTypesJson,
180
+ token_endpoint_auth_method AS tokenEndpointAuthMethod,
181
+ client_uri AS clientUri,
182
+ logo_uri AS logoUri,
183
+ contacts_json AS contactsJson,
184
+ tos_uri AS tosUri,
185
+ policy_uri AS policyUri,
186
+ software_id AS softwareId,
187
+ software_version AS softwareVersion,
188
+ client_id_issued_at AS clientIdIssuedAt,
189
+ client_secret_expires_at AS clientSecretExpiresAt
190
+ FROM mcp_oauth_clients
191
+ WHERE client_id = ?
192
+ LIMIT 1
193
+ `)
194
+ .bind(clientId)
195
+ .first();
196
+ if (!row)
197
+ return undefined;
198
+ return clientFromRow(row);
199
+ }
200
+ async registerClient(client) {
201
+ const clientId = createId("mcpcli");
202
+ const clientIdIssuedAt = nowEpochSeconds();
203
+ await this.db
204
+ .prepare(`
205
+ INSERT INTO mcp_oauth_clients (
206
+ client_id,
207
+ client_secret,
208
+ client_name,
209
+ redirect_uris_json,
210
+ scope,
211
+ grant_types_json,
212
+ response_types_json,
213
+ token_endpoint_auth_method,
214
+ client_uri,
215
+ logo_uri,
216
+ contacts_json,
217
+ tos_uri,
218
+ policy_uri,
219
+ software_id,
220
+ software_version,
221
+ client_id_issued_at,
222
+ client_secret_expires_at,
223
+ updated_at
224
+ ) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, CURRENT_TIMESTAMP)
225
+ `)
226
+ .bind(clientId, client.client_secret ?? null, client.client_name ?? null, jsonArray(client.redirect_uris), client.scope ?? this.options.defaultScope, jsonArray(client.grant_types), jsonArray(client.response_types), client.token_endpoint_auth_method ?? this.options.tokenEndpointAuthMethod, client.client_uri ?? null, client.logo_uri ?? null, jsonArray(client.contacts), client.tos_uri ?? null, client.policy_uri ?? null, client.software_id ?? null, client.software_version ?? null, clientIdIssuedAt, client.client_secret_expires_at ?? null)
227
+ .run();
228
+ const registered = await this.getClient(clientId);
229
+ if (!registered)
230
+ throw new Error("registered OAuth client missing");
231
+ return registered;
232
+ }
233
+ async createAuthorizationCode(input) {
234
+ const subjectColumns = this.options.subjectColumns.map((column) => quoteIdentifier(column.column));
235
+ const subjectValues = this.options.subjectColumns.map((column) => requiredSubject(input.subject, column.field));
236
+ await this.db
237
+ .prepare(`
238
+ INSERT INTO mcp_oauth_authorization_codes (
239
+ authorization_code_id,
240
+ code_hash,
241
+ client_id,
242
+ ${subjectColumns.join(",\n ")},
243
+ redirect_uri,
244
+ scopes_json,
245
+ resource,
246
+ code_challenge,
247
+ expires_at,
248
+ updated_at
249
+ ) VALUES (${["?", "?", "?", ...subjectValues.map(() => "?"), "?", "?", "?", "?", "?", "CURRENT_TIMESTAMP"].join(", ")})
250
+ `)
251
+ .bind(createId("mcpac"), await sha256Hex(input.code), input.clientId, ...subjectValues, input.redirectUri, jsonArray(input.scopes), input.resource, input.codeChallenge, input.expiresAt ?? nowEpochSeconds() + DEFAULT_AUTH_CODE_TTL_SECONDS)
252
+ .run();
253
+ }
254
+ async getAuthorizationCode(code) {
255
+ const subjectSelect = this.subjectSelectSql();
256
+ const row = await this.db
257
+ .prepare(`
258
+ SELECT
259
+ authorization_code_id AS authorizationCodeId,
260
+ client_id AS clientId,
261
+ ${subjectSelect}
262
+ redirect_uri AS redirectUri,
263
+ scopes_json AS scopesJson,
264
+ resource,
265
+ code_challenge AS codeChallenge,
266
+ expires_at AS expiresAt,
267
+ used_at AS usedAt
268
+ FROM mcp_oauth_authorization_codes
269
+ WHERE code_hash = ?
270
+ LIMIT 1
271
+ `)
272
+ .bind(await sha256Hex(code))
273
+ .first();
274
+ return row ? authorizationCodeFromRow(row, this.options.subjectColumns) : null;
275
+ }
276
+ async consumeAuthorizationCode(authorizationCodeId) {
277
+ await this.db
278
+ .prepare(`
279
+ UPDATE mcp_oauth_authorization_codes
280
+ SET used_at = CURRENT_TIMESTAMP, updated_at = CURRENT_TIMESTAMP
281
+ WHERE authorization_code_id = ?
282
+ `)
283
+ .bind(authorizationCodeId)
284
+ .run();
285
+ }
286
+ async createTokenSet(input) {
287
+ const subjectColumns = this.options.subjectColumns.map((column) => quoteIdentifier(column.column));
288
+ const subjectValues = this.options.subjectColumns.map((column) => requiredSubject(input.subject, column.field));
289
+ const tokenId = createId("mcptok");
290
+ await this.db
291
+ .prepare(`
292
+ INSERT INTO mcp_oauth_tokens (
293
+ token_id,
294
+ client_id,
295
+ ${subjectColumns.join(",\n ")},
296
+ access_token_hash,
297
+ refresh_token_hash,
298
+ scopes_json,
299
+ resource,
300
+ access_expires_at,
301
+ refresh_expires_at,
302
+ updated_at
303
+ ) VALUES (${["?", "?", ...subjectValues.map(() => "?"), "?", "?", "?", "?", "?", "?", "CURRENT_TIMESTAMP"].join(", ")})
304
+ `)
305
+ .bind(tokenId, input.clientId, ...subjectValues, await sha256Hex(input.accessToken), input.refreshToken ? await sha256Hex(input.refreshToken) : null, jsonArray(input.scopes), input.resource, input.accessExpiresAt, input.refreshExpiresAt)
306
+ .run();
307
+ return tokenId;
308
+ }
309
+ async getTokenByAccessToken(token) {
310
+ return this.getTokenByHashColumn("access_token_hash", token);
311
+ }
312
+ async getTokenByRefreshToken(token) {
313
+ return this.getTokenByHashColumn("refresh_token_hash", token);
314
+ }
315
+ async revokeToken(tokenId) {
316
+ await this.db
317
+ .prepare(`
318
+ UPDATE mcp_oauth_tokens
319
+ SET revoked_at = CURRENT_TIMESTAMP, updated_at = CURRENT_TIMESTAMP
320
+ WHERE token_id = ?
321
+ `)
322
+ .bind(tokenId)
323
+ .run();
324
+ }
325
+ async touchAccessToken(tokenId) {
326
+ await this.db
327
+ .prepare(`
328
+ UPDATE mcp_oauth_tokens
329
+ SET access_last_used_at = CURRENT_TIMESTAMP, updated_at = CURRENT_TIMESTAMP
330
+ WHERE token_id = ?
331
+ `)
332
+ .bind(tokenId)
333
+ .run();
334
+ }
335
+ async markTokenRotated(input) {
336
+ if (!this.options.refreshRotationColumns) {
337
+ await this.revokeToken(input.tokenId);
338
+ return true;
339
+ }
340
+ const result = await this.db
341
+ .prepare(`
342
+ UPDATE mcp_oauth_tokens
343
+ SET
344
+ revoked_at = CURRENT_TIMESTAMP,
345
+ rotated_to_token_id = ?,
346
+ refresh_reuse_expires_at = ?,
347
+ rotated_response_ciphertext = ?,
348
+ rotated_response_nonce = ?,
349
+ updated_at = CURRENT_TIMESTAMP
350
+ WHERE token_id = ? AND rotated_to_token_id IS NULL
351
+ `)
352
+ .bind(input.rotatedToTokenId, input.refreshReuseExpiresAt, input.rotatedResponseCiphertext, input.rotatedResponseNonce, input.tokenId)
353
+ .run();
354
+ return Number(result.meta.changes ?? 0) > 0;
355
+ }
356
+ async getTokenByHashColumn(column, token) {
357
+ const subjectSelect = this.subjectSelectSql();
358
+ const rotationSelect = this.options.refreshRotationColumns
359
+ ? `
360
+ rotated_to_token_id AS rotatedToTokenId,
361
+ refresh_reuse_expires_at AS refreshReuseExpiresAt,
362
+ rotated_response_ciphertext AS rotatedResponseCiphertext,
363
+ rotated_response_nonce AS rotatedResponseNonce,
364
+ `
365
+ : "";
366
+ const row = await this.db
367
+ .prepare(`
368
+ SELECT
369
+ token_id AS tokenId,
370
+ client_id AS clientId,
371
+ ${subjectSelect}
372
+ scopes_json AS scopesJson,
373
+ resource,
374
+ access_expires_at AS accessExpiresAt,
375
+ refresh_expires_at AS refreshExpiresAt,
376
+ revoked_at AS revokedAt,
377
+ ${rotationSelect}
378
+ token_id AS tokenIdAgain
379
+ FROM mcp_oauth_tokens
380
+ WHERE ${column} = ?
381
+ LIMIT 1
382
+ `)
383
+ .bind(await sha256Hex(token))
384
+ .first();
385
+ return row ? tokenFromRow(row, this.options.subjectColumns) : null;
386
+ }
387
+ subjectSelectSql() {
388
+ return this.options.subjectColumns.map((column) => `${quoteIdentifier(column.column)} AS ${quoteIdentifier(column.field)},`).join("\n ");
389
+ }
390
+ }
391
+ export async function issueMcpOAuthTokenSet(repository, input, options = {}) {
392
+ const accessToken = `${createToken("mcpat")}.${crypto.randomUUID().replace(/-/g, "")}`;
393
+ const refreshToken = `${createToken("mcprt")}.${crypto.randomUUID().replace(/-/g, "")}`;
394
+ const issuedAt = options.now?.() ?? nowEpochSeconds();
395
+ const accessExpiresAt = issuedAt + (options.accessTokenTtlSeconds ?? DEFAULT_ACCESS_TOKEN_TTL_SECONDS);
396
+ const refreshExpiresAt = issuedAt + (options.refreshTokenTtlSeconds ?? DEFAULT_REFRESH_TOKEN_TTL_SECONDS);
397
+ const tokenId = await repository.createTokenSet({
398
+ clientId: input.clientId,
399
+ subject: input.subject,
400
+ accessToken,
401
+ refreshToken,
402
+ scopes: input.scopes,
403
+ resource: input.resource?.href ?? null,
404
+ accessExpiresAt,
405
+ refreshExpiresAt,
406
+ });
407
+ return {
408
+ tokenId,
409
+ accessExpiresAt,
410
+ refreshExpiresAt,
411
+ tokens: {
412
+ access_token: accessToken,
413
+ token_type: "Bearer",
414
+ expires_in: options.accessTokenTtlSeconds ?? DEFAULT_ACCESS_TOKEN_TTL_SECONDS,
415
+ refresh_token: refreshToken,
416
+ scope: input.scopes.join(" "),
417
+ },
418
+ };
419
+ }
420
+ export function parseOAuthScope(scope) {
421
+ return scope?.split(/\s+/).filter(Boolean) ?? [];
422
+ }
423
+ export function parseOAuthJsonArray(value) {
424
+ if (!value)
425
+ return [];
426
+ try {
427
+ const parsed = JSON.parse(value);
428
+ return Array.isArray(parsed) ? parsed.filter((item) => typeof item === "string") : [];
429
+ }
430
+ catch {
431
+ return [];
432
+ }
433
+ }
434
+ export function createOAuthRedirect(redirectUri, params) {
435
+ const url = new URL(redirectUri);
436
+ for (const [key, value] of Object.entries(params)) {
437
+ if (value !== undefined)
438
+ url.searchParams.set(key, value);
439
+ }
440
+ return url.toString();
441
+ }
442
+ export async function encryptOAuthTokenResponse(tokens, secret) {
443
+ const nonce = crypto.getRandomValues(new Uint8Array(12));
444
+ const key = await tokenResponseEncryptionKey(secret);
445
+ const ciphertext = await crypto.subtle.encrypt({ name: "AES-GCM", iv: nonce }, key, new TextEncoder().encode(JSON.stringify(tokens)));
446
+ return {
447
+ ciphertext: toBase64Url(new Uint8Array(ciphertext)),
448
+ nonce: toBase64Url(nonce),
449
+ };
450
+ }
451
+ export async function decryptOAuthTokenResponse(ciphertext, nonce, secret) {
452
+ try {
453
+ const key = await tokenResponseEncryptionKey(secret);
454
+ const plaintext = await crypto.subtle.decrypt({ name: "AES-GCM", iv: toArrayBuffer(fromBase64Url(nonce)) }, key, toArrayBuffer(fromBase64Url(ciphertext)));
455
+ return JSON.parse(new TextDecoder().decode(plaintext));
456
+ }
457
+ catch {
458
+ return null;
459
+ }
460
+ }
151
461
  function setExtraSearchParams(url, params) {
152
462
  for (const [key, value] of Object.entries(params ?? {})) {
153
463
  if (value !== undefined)
154
464
  url.searchParams.set(key, value);
155
465
  }
156
466
  }
467
+ function clientFromRow(row) {
468
+ return {
469
+ client_id: row.clientId,
470
+ client_secret: row.clientSecret ?? undefined,
471
+ client_name: row.clientName ?? undefined,
472
+ redirect_uris: parseOAuthJsonArray(row.redirectUrisJson),
473
+ scope: row.scope ?? undefined,
474
+ grant_types: parseOAuthJsonArray(row.grantTypesJson),
475
+ response_types: parseOAuthJsonArray(row.responseTypesJson),
476
+ token_endpoint_auth_method: row.tokenEndpointAuthMethod ?? undefined,
477
+ client_uri: row.clientUri ?? undefined,
478
+ logo_uri: row.logoUri ?? undefined,
479
+ contacts: parseOAuthJsonArray(row.contactsJson),
480
+ tos_uri: row.tosUri ?? undefined,
481
+ policy_uri: row.policyUri ?? undefined,
482
+ software_id: row.softwareId ?? undefined,
483
+ software_version: row.softwareVersion ?? undefined,
484
+ client_id_issued_at: row.clientIdIssuedAt ?? undefined,
485
+ client_secret_expires_at: row.clientSecretExpiresAt ?? undefined,
486
+ };
487
+ }
488
+ function authorizationCodeFromRow(row, subjectColumns) {
489
+ return {
490
+ authorizationCodeId: row.authorizationCodeId,
491
+ clientId: row.clientId,
492
+ redirectUri: row.redirectUri,
493
+ scopesJson: row.scopesJson,
494
+ resource: row.resource,
495
+ codeChallenge: row.codeChallenge,
496
+ expiresAt: row.expiresAt,
497
+ usedAt: row.usedAt,
498
+ subject: subjectFromRow(row, subjectColumns),
499
+ };
500
+ }
501
+ function tokenFromRow(row, subjectColumns) {
502
+ return {
503
+ tokenId: row.tokenId,
504
+ clientId: row.clientId,
505
+ scopesJson: row.scopesJson,
506
+ resource: row.resource,
507
+ accessExpiresAt: row.accessExpiresAt,
508
+ refreshExpiresAt: row.refreshExpiresAt,
509
+ revokedAt: row.revokedAt,
510
+ subject: subjectFromRow(row, subjectColumns),
511
+ rotatedToTokenId: row.rotatedToTokenId,
512
+ refreshReuseExpiresAt: row.refreshReuseExpiresAt,
513
+ rotatedResponseCiphertext: row.rotatedResponseCiphertext,
514
+ rotatedResponseNonce: row.rotatedResponseNonce,
515
+ };
516
+ }
517
+ function subjectFromRow(row, subjectColumns) {
518
+ const subject = {};
519
+ for (const column of subjectColumns) {
520
+ const value = row[column.field];
521
+ if (typeof value === "string")
522
+ subject[column.field] = value;
523
+ }
524
+ return subject;
525
+ }
526
+ function requiredSubject(subject, field) {
527
+ const value = subject[field];
528
+ if (!value)
529
+ throw new Error(`Missing OAuth subject field: ${field}`);
530
+ return value;
531
+ }
532
+ function jsonArray(value) {
533
+ return JSON.stringify(value ?? []);
534
+ }
535
+ function nowEpochSeconds() {
536
+ return Math.floor(Date.now() / 1000);
537
+ }
538
+ function quoteIdentifier(value) {
539
+ if (!/^[A-Za-z_][A-Za-z0-9_]*$/.test(value)) {
540
+ throw new Error(`Unsafe SQL identifier: ${value}`);
541
+ }
542
+ return `"${value}"`;
543
+ }
544
+ async function tokenResponseEncryptionKey(secret) {
545
+ const digest = await crypto.subtle.digest("SHA-256", new TextEncoder().encode(secret));
546
+ return crypto.subtle.importKey("raw", digest, { name: "AES-GCM" }, false, ["encrypt", "decrypt"]);
547
+ }
548
+ function toArrayBuffer(bytes) {
549
+ return bytes.buffer.slice(bytes.byteOffset, bytes.byteOffset + bytes.byteLength);
550
+ }
157
551
  //# sourceMappingURL=oauth.js.map
package/dist/oauth.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"oauth.js","sourceRoot":"","sources":["../src/oauth.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"oauth.js","sourceRoot":"","sources":["../src/oauth.ts"],"names":[],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@q32/core",
3
- "version": "0.1.14",
3
+ "version": "0.1.16",
4
4
  "description": "Shared TypeScript primitives for Q32 Cloudflare Worker projects.",
5
5
  "license": "MIT",
6
6
  "type": "module",
package/src/oauth.ts CHANGED
@@ -1,5 +1,8 @@
1
1
  import type { FetchLike } from "./http.js";
2
2
  import { defaultFetch } from "./http.js";
3
+ import type { D1DatabaseLike } from "./d1.js";
4
+ import { sha256Hex } from "./hash.js";
5
+ import { createId, createToken, fromBase64Url, toBase64Url } from "./ids.js";
3
6
 
4
7
  export type OAuthMetadataOptions = {
5
8
  issuer: string;
@@ -77,6 +80,93 @@ export type GitHubUserProfile = {
77
80
  avatar_url: string | null;
78
81
  };
79
82
 
83
+ export type OAuthClientInformation = {
84
+ client_id: string;
85
+ client_secret?: string;
86
+ client_name?: string;
87
+ redirect_uris?: string[];
88
+ scope?: string;
89
+ grant_types?: string[];
90
+ response_types?: string[];
91
+ token_endpoint_auth_method?: string;
92
+ client_uri?: string;
93
+ logo_uri?: string;
94
+ contacts?: string[];
95
+ tos_uri?: string;
96
+ policy_uri?: string;
97
+ software_id?: string;
98
+ software_version?: string;
99
+ client_id_issued_at?: number;
100
+ client_secret_expires_at?: number;
101
+ };
102
+
103
+ export type OAuthClientRegistration = Omit<OAuthClientInformation, "client_id" | "client_id_issued_at">;
104
+
105
+ export type OAuthTokens = {
106
+ access_token: string;
107
+ token_type: "Bearer";
108
+ expires_in: number;
109
+ refresh_token?: string;
110
+ scope?: string;
111
+ };
112
+
113
+ export type McpOAuthSubjectColumn = {
114
+ field: string;
115
+ column: string;
116
+ };
117
+
118
+ export type McpOAuthRepositoryOptions = {
119
+ defaultScope?: string;
120
+ tokenEndpointAuthMethod?: string;
121
+ subjectColumns?: McpOAuthSubjectColumn[];
122
+ refreshRotationColumns?: boolean;
123
+ };
124
+
125
+ export type McpAuthorizationCodeRow = {
126
+ authorizationCodeId: string;
127
+ clientId: string;
128
+ redirectUri: string;
129
+ scopesJson: string;
130
+ resource: string | null;
131
+ codeChallenge: string;
132
+ expiresAt: number;
133
+ usedAt: string | null;
134
+ subject: Record<string, string>;
135
+ };
136
+
137
+ export type McpTokenRow = {
138
+ tokenId: string;
139
+ clientId: string;
140
+ scopesJson: string;
141
+ resource: string | null;
142
+ accessExpiresAt: number;
143
+ refreshExpiresAt: number | null;
144
+ revokedAt: string | null;
145
+ subject: Record<string, string>;
146
+ rotatedToTokenId?: string | null;
147
+ refreshReuseExpiresAt?: number | null;
148
+ rotatedResponseCiphertext?: string | null;
149
+ rotatedResponseNonce?: string | null;
150
+ };
151
+
152
+ export type McpIssuedTokenSet = {
153
+ tokenId: string;
154
+ tokens: OAuthTokens;
155
+ accessExpiresAt: number;
156
+ refreshExpiresAt: number | null;
157
+ };
158
+
159
+ export type McpOAuthTokenOptions = {
160
+ accessTokenTtlSeconds?: number;
161
+ refreshTokenTtlSeconds?: number;
162
+ now?: () => number;
163
+ };
164
+
165
+ const DEFAULT_MCP_SUBJECT_COLUMNS: McpOAuthSubjectColumn[] = [{ field: "accountId", column: "account_id" }];
166
+ const DEFAULT_AUTH_CODE_TTL_SECONDS = 10 * 60;
167
+ const DEFAULT_ACCESS_TOKEN_TTL_SECONDS = 60 * 60;
168
+ const DEFAULT_REFRESH_TOKEN_TTL_SECONDS = 30 * 24 * 60 * 60;
169
+
80
170
  export class GoogleOAuthClient {
81
171
  constructor(private readonly fetchImpl: FetchLike = defaultFetch) {}
82
172
 
@@ -122,7 +212,7 @@ export class GoogleOAuthClient {
122
212
  if (!response.ok) throw new Error(`Google profile fetch failed: ${response.status}`);
123
213
  const profile = (await response.json()) as GoogleUserProfile;
124
214
  if (!profile.sub || !profile.email) throw new Error("Google profile missing identity fields");
125
- if (options.requireVerifiedEmail && profile.email_verified === false) throw new Error("Google profile email is not verified");
215
+ if (options.requireVerifiedEmail && profile.email_verified === false) throw new Error("Google profile missing verified identity fields");
126
216
  return profile;
127
217
  }
128
218
  }
@@ -197,8 +287,558 @@ export class GitHubOAuthClient {
197
287
  }
198
288
  }
199
289
 
290
+ export class McpOAuthRepository {
291
+ private readonly options: Required<Pick<McpOAuthRepositoryOptions, "defaultScope" | "tokenEndpointAuthMethod" | "subjectColumns" | "refreshRotationColumns">>;
292
+
293
+ constructor(
294
+ private readonly db: D1DatabaseLike,
295
+ options: McpOAuthRepositoryOptions = {},
296
+ ) {
297
+ this.options = {
298
+ defaultScope: options.defaultScope ?? "mcp:read",
299
+ tokenEndpointAuthMethod: options.tokenEndpointAuthMethod ?? "none",
300
+ subjectColumns: options.subjectColumns ?? DEFAULT_MCP_SUBJECT_COLUMNS,
301
+ refreshRotationColumns: options.refreshRotationColumns ?? false,
302
+ };
303
+ }
304
+
305
+ async getClient(clientId: string): Promise<OAuthClientInformation | undefined> {
306
+ const row = await this.db
307
+ .prepare(
308
+ `
309
+ SELECT
310
+ client_id AS clientId,
311
+ client_secret AS clientSecret,
312
+ client_name AS clientName,
313
+ redirect_uris_json AS redirectUrisJson,
314
+ scope,
315
+ grant_types_json AS grantTypesJson,
316
+ response_types_json AS responseTypesJson,
317
+ token_endpoint_auth_method AS tokenEndpointAuthMethod,
318
+ client_uri AS clientUri,
319
+ logo_uri AS logoUri,
320
+ contacts_json AS contactsJson,
321
+ tos_uri AS tosUri,
322
+ policy_uri AS policyUri,
323
+ software_id AS softwareId,
324
+ software_version AS softwareVersion,
325
+ client_id_issued_at AS clientIdIssuedAt,
326
+ client_secret_expires_at AS clientSecretExpiresAt
327
+ FROM mcp_oauth_clients
328
+ WHERE client_id = ?
329
+ LIMIT 1
330
+ `,
331
+ )
332
+ .bind(clientId)
333
+ .first<OAuthClientRow>();
334
+
335
+ if (!row) return undefined;
336
+ return clientFromRow(row);
337
+ }
338
+
339
+ async registerClient(client: OAuthClientRegistration): Promise<OAuthClientInformation> {
340
+ const clientId = createId("mcpcli");
341
+ const clientIdIssuedAt = nowEpochSeconds();
342
+ await this.db
343
+ .prepare(
344
+ `
345
+ INSERT INTO mcp_oauth_clients (
346
+ client_id,
347
+ client_secret,
348
+ client_name,
349
+ redirect_uris_json,
350
+ scope,
351
+ grant_types_json,
352
+ response_types_json,
353
+ token_endpoint_auth_method,
354
+ client_uri,
355
+ logo_uri,
356
+ contacts_json,
357
+ tos_uri,
358
+ policy_uri,
359
+ software_id,
360
+ software_version,
361
+ client_id_issued_at,
362
+ client_secret_expires_at,
363
+ updated_at
364
+ ) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, CURRENT_TIMESTAMP)
365
+ `,
366
+ )
367
+ .bind(
368
+ clientId,
369
+ client.client_secret ?? null,
370
+ client.client_name ?? null,
371
+ jsonArray(client.redirect_uris),
372
+ client.scope ?? this.options.defaultScope,
373
+ jsonArray(client.grant_types),
374
+ jsonArray(client.response_types),
375
+ client.token_endpoint_auth_method ?? this.options.tokenEndpointAuthMethod,
376
+ client.client_uri ?? null,
377
+ client.logo_uri ?? null,
378
+ jsonArray(client.contacts),
379
+ client.tos_uri ?? null,
380
+ client.policy_uri ?? null,
381
+ client.software_id ?? null,
382
+ client.software_version ?? null,
383
+ clientIdIssuedAt,
384
+ client.client_secret_expires_at ?? null,
385
+ )
386
+ .run();
387
+
388
+ const registered = await this.getClient(clientId);
389
+ if (!registered) throw new Error("registered OAuth client missing");
390
+ return registered;
391
+ }
392
+
393
+ async createAuthorizationCode(input: {
394
+ code: string;
395
+ clientId: string;
396
+ subject: Record<string, string>;
397
+ redirectUri: string;
398
+ scopes: string[];
399
+ resource: string | null;
400
+ codeChallenge: string;
401
+ expiresAt?: number;
402
+ }): Promise<void> {
403
+ const subjectColumns = this.options.subjectColumns.map((column) => quoteIdentifier(column.column));
404
+ const subjectValues = this.options.subjectColumns.map((column) => requiredSubject(input.subject, column.field));
405
+ await this.db
406
+ .prepare(
407
+ `
408
+ INSERT INTO mcp_oauth_authorization_codes (
409
+ authorization_code_id,
410
+ code_hash,
411
+ client_id,
412
+ ${subjectColumns.join(",\n ")},
413
+ redirect_uri,
414
+ scopes_json,
415
+ resource,
416
+ code_challenge,
417
+ expires_at,
418
+ updated_at
419
+ ) VALUES (${["?", "?", "?", ...subjectValues.map(() => "?"), "?", "?", "?", "?", "?", "CURRENT_TIMESTAMP"].join(", ")})
420
+ `,
421
+ )
422
+ .bind(
423
+ createId("mcpac"),
424
+ await sha256Hex(input.code),
425
+ input.clientId,
426
+ ...subjectValues,
427
+ input.redirectUri,
428
+ jsonArray(input.scopes),
429
+ input.resource,
430
+ input.codeChallenge,
431
+ input.expiresAt ?? nowEpochSeconds() + DEFAULT_AUTH_CODE_TTL_SECONDS,
432
+ )
433
+ .run();
434
+ }
435
+
436
+ async getAuthorizationCode(code: string): Promise<McpAuthorizationCodeRow | null> {
437
+ const subjectSelect = this.subjectSelectSql();
438
+ const row = await this.db
439
+ .prepare(
440
+ `
441
+ SELECT
442
+ authorization_code_id AS authorizationCodeId,
443
+ client_id AS clientId,
444
+ ${subjectSelect}
445
+ redirect_uri AS redirectUri,
446
+ scopes_json AS scopesJson,
447
+ resource,
448
+ code_challenge AS codeChallenge,
449
+ expires_at AS expiresAt,
450
+ used_at AS usedAt
451
+ FROM mcp_oauth_authorization_codes
452
+ WHERE code_hash = ?
453
+ LIMIT 1
454
+ `,
455
+ )
456
+ .bind(await sha256Hex(code))
457
+ .first<AuthorizationCodeStorageRow>();
458
+ return row ? authorizationCodeFromRow(row, this.options.subjectColumns) : null;
459
+ }
460
+
461
+ async consumeAuthorizationCode(authorizationCodeId: string): Promise<void> {
462
+ await this.db
463
+ .prepare(
464
+ `
465
+ UPDATE mcp_oauth_authorization_codes
466
+ SET used_at = CURRENT_TIMESTAMP, updated_at = CURRENT_TIMESTAMP
467
+ WHERE authorization_code_id = ?
468
+ `,
469
+ )
470
+ .bind(authorizationCodeId)
471
+ .run();
472
+ }
473
+
474
+ async createTokenSet(input: {
475
+ clientId: string;
476
+ subject: Record<string, string>;
477
+ accessToken: string;
478
+ refreshToken: string | null;
479
+ scopes: string[];
480
+ resource: string | null;
481
+ accessExpiresAt: number;
482
+ refreshExpiresAt: number | null;
483
+ }): Promise<string> {
484
+ const subjectColumns = this.options.subjectColumns.map((column) => quoteIdentifier(column.column));
485
+ const subjectValues = this.options.subjectColumns.map((column) => requiredSubject(input.subject, column.field));
486
+ const tokenId = createId("mcptok");
487
+ await this.db
488
+ .prepare(
489
+ `
490
+ INSERT INTO mcp_oauth_tokens (
491
+ token_id,
492
+ client_id,
493
+ ${subjectColumns.join(",\n ")},
494
+ access_token_hash,
495
+ refresh_token_hash,
496
+ scopes_json,
497
+ resource,
498
+ access_expires_at,
499
+ refresh_expires_at,
500
+ updated_at
501
+ ) VALUES (${["?", "?", ...subjectValues.map(() => "?"), "?", "?", "?", "?", "?", "?", "CURRENT_TIMESTAMP"].join(", ")})
502
+ `,
503
+ )
504
+ .bind(
505
+ tokenId,
506
+ input.clientId,
507
+ ...subjectValues,
508
+ await sha256Hex(input.accessToken),
509
+ input.refreshToken ? await sha256Hex(input.refreshToken) : null,
510
+ jsonArray(input.scopes),
511
+ input.resource,
512
+ input.accessExpiresAt,
513
+ input.refreshExpiresAt,
514
+ )
515
+ .run();
516
+ return tokenId;
517
+ }
518
+
519
+ async getTokenByAccessToken(token: string): Promise<McpTokenRow | null> {
520
+ return this.getTokenByHashColumn("access_token_hash", token);
521
+ }
522
+
523
+ async getTokenByRefreshToken(token: string): Promise<McpTokenRow | null> {
524
+ return this.getTokenByHashColumn("refresh_token_hash", token);
525
+ }
526
+
527
+ async revokeToken(tokenId: string): Promise<void> {
528
+ await this.db
529
+ .prepare(
530
+ `
531
+ UPDATE mcp_oauth_tokens
532
+ SET revoked_at = CURRENT_TIMESTAMP, updated_at = CURRENT_TIMESTAMP
533
+ WHERE token_id = ?
534
+ `,
535
+ )
536
+ .bind(tokenId)
537
+ .run();
538
+ }
539
+
540
+ async touchAccessToken(tokenId: string): Promise<void> {
541
+ await this.db
542
+ .prepare(
543
+ `
544
+ UPDATE mcp_oauth_tokens
545
+ SET access_last_used_at = CURRENT_TIMESTAMP, updated_at = CURRENT_TIMESTAMP
546
+ WHERE token_id = ?
547
+ `,
548
+ )
549
+ .bind(tokenId)
550
+ .run();
551
+ }
552
+
553
+ async markTokenRotated(input: {
554
+ tokenId: string;
555
+ rotatedToTokenId: string;
556
+ refreshReuseExpiresAt: number;
557
+ rotatedResponseCiphertext: string;
558
+ rotatedResponseNonce: string;
559
+ }): Promise<boolean> {
560
+ if (!this.options.refreshRotationColumns) {
561
+ await this.revokeToken(input.tokenId);
562
+ return true;
563
+ }
564
+ const result = await this.db
565
+ .prepare(
566
+ `
567
+ UPDATE mcp_oauth_tokens
568
+ SET
569
+ revoked_at = CURRENT_TIMESTAMP,
570
+ rotated_to_token_id = ?,
571
+ refresh_reuse_expires_at = ?,
572
+ rotated_response_ciphertext = ?,
573
+ rotated_response_nonce = ?,
574
+ updated_at = CURRENT_TIMESTAMP
575
+ WHERE token_id = ? AND rotated_to_token_id IS NULL
576
+ `,
577
+ )
578
+ .bind(input.rotatedToTokenId, input.refreshReuseExpiresAt, input.rotatedResponseCiphertext, input.rotatedResponseNonce, input.tokenId)
579
+ .run();
580
+ return Number(result.meta.changes ?? 0) > 0;
581
+ }
582
+
583
+ private async getTokenByHashColumn(column: "access_token_hash" | "refresh_token_hash", token: string): Promise<McpTokenRow | null> {
584
+ const subjectSelect = this.subjectSelectSql();
585
+ const rotationSelect = this.options.refreshRotationColumns
586
+ ? `
587
+ rotated_to_token_id AS rotatedToTokenId,
588
+ refresh_reuse_expires_at AS refreshReuseExpiresAt,
589
+ rotated_response_ciphertext AS rotatedResponseCiphertext,
590
+ rotated_response_nonce AS rotatedResponseNonce,
591
+ `
592
+ : "";
593
+ const row = await this.db
594
+ .prepare(
595
+ `
596
+ SELECT
597
+ token_id AS tokenId,
598
+ client_id AS clientId,
599
+ ${subjectSelect}
600
+ scopes_json AS scopesJson,
601
+ resource,
602
+ access_expires_at AS accessExpiresAt,
603
+ refresh_expires_at AS refreshExpiresAt,
604
+ revoked_at AS revokedAt,
605
+ ${rotationSelect}
606
+ token_id AS tokenIdAgain
607
+ FROM mcp_oauth_tokens
608
+ WHERE ${column} = ?
609
+ LIMIT 1
610
+ `,
611
+ )
612
+ .bind(await sha256Hex(token))
613
+ .first<TokenStorageRow>();
614
+ return row ? tokenFromRow(row, this.options.subjectColumns) : null;
615
+ }
616
+
617
+ private subjectSelectSql(): string {
618
+ return this.options.subjectColumns.map((column) => `${quoteIdentifier(column.column)} AS ${quoteIdentifier(column.field)},`).join("\n ");
619
+ }
620
+ }
621
+
622
+ export async function issueMcpOAuthTokenSet(
623
+ repository: McpOAuthRepository,
624
+ input: {
625
+ clientId: string;
626
+ subject: Record<string, string>;
627
+ scopes: string[];
628
+ resource?: URL | null;
629
+ },
630
+ options: McpOAuthTokenOptions = {},
631
+ ): Promise<McpIssuedTokenSet> {
632
+ const accessToken = `${createToken("mcpat")}.${crypto.randomUUID().replace(/-/g, "")}`;
633
+ const refreshToken = `${createToken("mcprt")}.${crypto.randomUUID().replace(/-/g, "")}`;
634
+ const issuedAt = options.now?.() ?? nowEpochSeconds();
635
+ const accessExpiresAt = issuedAt + (options.accessTokenTtlSeconds ?? DEFAULT_ACCESS_TOKEN_TTL_SECONDS);
636
+ const refreshExpiresAt = issuedAt + (options.refreshTokenTtlSeconds ?? DEFAULT_REFRESH_TOKEN_TTL_SECONDS);
637
+ const tokenId = await repository.createTokenSet({
638
+ clientId: input.clientId,
639
+ subject: input.subject,
640
+ accessToken,
641
+ refreshToken,
642
+ scopes: input.scopes,
643
+ resource: input.resource?.href ?? null,
644
+ accessExpiresAt,
645
+ refreshExpiresAt,
646
+ });
647
+ return {
648
+ tokenId,
649
+ accessExpiresAt,
650
+ refreshExpiresAt,
651
+ tokens: {
652
+ access_token: accessToken,
653
+ token_type: "Bearer",
654
+ expires_in: options.accessTokenTtlSeconds ?? DEFAULT_ACCESS_TOKEN_TTL_SECONDS,
655
+ refresh_token: refreshToken,
656
+ scope: input.scopes.join(" "),
657
+ },
658
+ };
659
+ }
660
+
661
+ export function parseOAuthScope(scope: string | null | undefined): string[] {
662
+ return scope?.split(/\s+/).filter(Boolean) ?? [];
663
+ }
664
+
665
+ export function parseOAuthJsonArray(value: string | null | undefined): string[] {
666
+ if (!value) return [];
667
+ try {
668
+ const parsed = JSON.parse(value) as unknown;
669
+ return Array.isArray(parsed) ? parsed.filter((item): item is string => typeof item === "string") : [];
670
+ } catch {
671
+ return [];
672
+ }
673
+ }
674
+
675
+ export function createOAuthRedirect(redirectUri: string, params: Record<string, string | undefined>): string {
676
+ const url = new URL(redirectUri);
677
+ for (const [key, value] of Object.entries(params)) {
678
+ if (value !== undefined) url.searchParams.set(key, value);
679
+ }
680
+ return url.toString();
681
+ }
682
+
683
+ export async function encryptOAuthTokenResponse(tokens: OAuthTokens, secret: string): Promise<{ ciphertext: string; nonce: string }> {
684
+ const nonce = crypto.getRandomValues(new Uint8Array(12));
685
+ const key = await tokenResponseEncryptionKey(secret);
686
+ const ciphertext = await crypto.subtle.encrypt({ name: "AES-GCM", iv: nonce }, key, new TextEncoder().encode(JSON.stringify(tokens)));
687
+ return {
688
+ ciphertext: toBase64Url(new Uint8Array(ciphertext)),
689
+ nonce: toBase64Url(nonce),
690
+ };
691
+ }
692
+
693
+ export async function decryptOAuthTokenResponse(ciphertext: string, nonce: string, secret: string): Promise<OAuthTokens | null> {
694
+ try {
695
+ const key = await tokenResponseEncryptionKey(secret);
696
+ const plaintext = await crypto.subtle.decrypt({ name: "AES-GCM", iv: toArrayBuffer(fromBase64Url(nonce)) }, key, toArrayBuffer(fromBase64Url(ciphertext)));
697
+ return JSON.parse(new TextDecoder().decode(plaintext)) as OAuthTokens;
698
+ } catch {
699
+ return null;
700
+ }
701
+ }
702
+
200
703
  function setExtraSearchParams(url: URL, params: Record<string, string | undefined> | undefined): void {
201
704
  for (const [key, value] of Object.entries(params ?? {})) {
202
705
  if (value !== undefined) url.searchParams.set(key, value);
203
706
  }
204
707
  }
708
+
709
+ type OAuthClientRow = {
710
+ clientId: string;
711
+ clientSecret: string | null;
712
+ clientName: string | null;
713
+ redirectUrisJson: string;
714
+ scope: string | null;
715
+ grantTypesJson: string | null;
716
+ responseTypesJson: string | null;
717
+ tokenEndpointAuthMethod: string | null;
718
+ clientUri: string | null;
719
+ logoUri: string | null;
720
+ contactsJson: string | null;
721
+ tosUri: string | null;
722
+ policyUri: string | null;
723
+ softwareId: string | null;
724
+ softwareVersion: string | null;
725
+ clientIdIssuedAt: number | null;
726
+ clientSecretExpiresAt: number | null;
727
+ };
728
+
729
+ type AuthorizationCodeStorageRow = {
730
+ authorizationCodeId: string;
731
+ clientId: string;
732
+ redirectUri: string;
733
+ scopesJson: string;
734
+ resource: string | null;
735
+ codeChallenge: string;
736
+ expiresAt: number;
737
+ usedAt: string | null;
738
+ } & Record<string, string | number | null>;
739
+
740
+ type TokenStorageRow = {
741
+ tokenId: string;
742
+ clientId: string;
743
+ scopesJson: string;
744
+ resource: string | null;
745
+ accessExpiresAt: number;
746
+ refreshExpiresAt: number | null;
747
+ revokedAt: string | null;
748
+ rotatedToTokenId?: string | null;
749
+ refreshReuseExpiresAt?: number | null;
750
+ rotatedResponseCiphertext?: string | null;
751
+ rotatedResponseNonce?: string | null;
752
+ } & Record<string, string | number | null | undefined>;
753
+
754
+ function clientFromRow(row: OAuthClientRow): OAuthClientInformation {
755
+ return {
756
+ client_id: row.clientId,
757
+ client_secret: row.clientSecret ?? undefined,
758
+ client_name: row.clientName ?? undefined,
759
+ redirect_uris: parseOAuthJsonArray(row.redirectUrisJson),
760
+ scope: row.scope ?? undefined,
761
+ grant_types: parseOAuthJsonArray(row.grantTypesJson),
762
+ response_types: parseOAuthJsonArray(row.responseTypesJson),
763
+ token_endpoint_auth_method: row.tokenEndpointAuthMethod ?? undefined,
764
+ client_uri: row.clientUri ?? undefined,
765
+ logo_uri: row.logoUri ?? undefined,
766
+ contacts: parseOAuthJsonArray(row.contactsJson),
767
+ tos_uri: row.tosUri ?? undefined,
768
+ policy_uri: row.policyUri ?? undefined,
769
+ software_id: row.softwareId ?? undefined,
770
+ software_version: row.softwareVersion ?? undefined,
771
+ client_id_issued_at: row.clientIdIssuedAt ?? undefined,
772
+ client_secret_expires_at: row.clientSecretExpiresAt ?? undefined,
773
+ };
774
+ }
775
+
776
+ function authorizationCodeFromRow(row: AuthorizationCodeStorageRow, subjectColumns: McpOAuthSubjectColumn[]): McpAuthorizationCodeRow {
777
+ return {
778
+ authorizationCodeId: row.authorizationCodeId,
779
+ clientId: row.clientId,
780
+ redirectUri: row.redirectUri,
781
+ scopesJson: row.scopesJson,
782
+ resource: row.resource,
783
+ codeChallenge: row.codeChallenge,
784
+ expiresAt: row.expiresAt,
785
+ usedAt: row.usedAt,
786
+ subject: subjectFromRow(row, subjectColumns),
787
+ };
788
+ }
789
+
790
+ function tokenFromRow(row: TokenStorageRow, subjectColumns: McpOAuthSubjectColumn[]): McpTokenRow {
791
+ return {
792
+ tokenId: row.tokenId,
793
+ clientId: row.clientId,
794
+ scopesJson: row.scopesJson,
795
+ resource: row.resource,
796
+ accessExpiresAt: row.accessExpiresAt,
797
+ refreshExpiresAt: row.refreshExpiresAt,
798
+ revokedAt: row.revokedAt,
799
+ subject: subjectFromRow(row, subjectColumns),
800
+ rotatedToTokenId: row.rotatedToTokenId,
801
+ refreshReuseExpiresAt: row.refreshReuseExpiresAt,
802
+ rotatedResponseCiphertext: row.rotatedResponseCiphertext,
803
+ rotatedResponseNonce: row.rotatedResponseNonce,
804
+ };
805
+ }
806
+
807
+ function subjectFromRow(row: Record<string, string | number | null | undefined>, subjectColumns: McpOAuthSubjectColumn[]): Record<string, string> {
808
+ const subject: Record<string, string> = {};
809
+ for (const column of subjectColumns) {
810
+ const value = row[column.field];
811
+ if (typeof value === "string") subject[column.field] = value;
812
+ }
813
+ return subject;
814
+ }
815
+
816
+ function requiredSubject(subject: Record<string, string>, field: string): string {
817
+ const value = subject[field];
818
+ if (!value) throw new Error(`Missing OAuth subject field: ${field}`);
819
+ return value;
820
+ }
821
+
822
+ function jsonArray(value: string[] | null | undefined): string {
823
+ return JSON.stringify(value ?? []);
824
+ }
825
+
826
+ function nowEpochSeconds(): number {
827
+ return Math.floor(Date.now() / 1000);
828
+ }
829
+
830
+ function quoteIdentifier(value: string): string {
831
+ if (!/^[A-Za-z_][A-Za-z0-9_]*$/.test(value)) {
832
+ throw new Error(`Unsafe SQL identifier: ${value}`);
833
+ }
834
+ return `"${value}"`;
835
+ }
836
+
837
+ async function tokenResponseEncryptionKey(secret: string): Promise<CryptoKey> {
838
+ const digest = await crypto.subtle.digest("SHA-256", new TextEncoder().encode(secret));
839
+ return crypto.subtle.importKey("raw", digest, { name: "AES-GCM" }, false, ["encrypt", "decrypt"]);
840
+ }
841
+
842
+ function toArrayBuffer(bytes: Uint8Array): ArrayBuffer {
843
+ return bytes.buffer.slice(bytes.byteOffset, bytes.byteOffset + bytes.byteLength) as ArrayBuffer;
844
+ }