@jeffjassky/oauth-host 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 +9 -1
- package/dist/index.cjs +50 -1
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +46 -2
- package/dist/index.js.map +1 -1
- package/package.json +2 -2
- package/types/test-d.ts +0 -320
package/dist/index.js
CHANGED
|
@@ -493,6 +493,7 @@ function resolveConfig(config) {
|
|
|
493
493
|
}
|
|
494
494
|
const store = rateLimits.store ?? memoryStore();
|
|
495
495
|
const normalizedMount = `/${String(mountPath).replace(/^\/+|\/+$/g, "")}`;
|
|
496
|
+
const indexes = { ready: false };
|
|
496
497
|
const ctx = {
|
|
497
498
|
models,
|
|
498
499
|
issuer,
|
|
@@ -524,6 +525,11 @@ function resolveConfig(config) {
|
|
|
524
525
|
cors: { tokenEndpoint: cors.tokenEndpoint ?? false, origins: cors.origins ?? [] },
|
|
525
526
|
clockSkewMs,
|
|
526
527
|
cimd: resolveCimd(clientIdMetadata, scopeIndex),
|
|
528
|
+
indexes,
|
|
529
|
+
async syncIndexes() {
|
|
530
|
+
await syncModelIndexes(models);
|
|
531
|
+
indexes.ready = true;
|
|
532
|
+
},
|
|
527
533
|
logger,
|
|
528
534
|
track,
|
|
529
535
|
async audit(entry) {
|
|
@@ -2473,8 +2479,17 @@ function createOAuthRouter(ctx) {
|
|
|
2473
2479
|
const ipKey = (req) => req.ip ?? "unknown";
|
|
2474
2480
|
const clientKey = (req) => clientIdFromRequest(req) ?? ipKey(req);
|
|
2475
2481
|
const cors = corsMiddleware(ctx);
|
|
2482
|
+
const requireIndexes = w((_req, _res, next) => {
|
|
2483
|
+
if (ctx.indexes.ready) return next();
|
|
2484
|
+
throw new OAuthError(
|
|
2485
|
+
503,
|
|
2486
|
+
"server_error",
|
|
2487
|
+
"This authorization server is not ready: `syncIndexes()` has not resolved yet. Await `oauth.syncIndexes()` at boot, before mounting the routers."
|
|
2488
|
+
);
|
|
2489
|
+
});
|
|
2476
2490
|
router.get(
|
|
2477
2491
|
"/authorize",
|
|
2492
|
+
requireIndexes,
|
|
2478
2493
|
rateLimit(ctx, "authorize", ipKey),
|
|
2479
2494
|
w(async (req, res) => {
|
|
2480
2495
|
let validated;
|
|
@@ -2533,6 +2548,7 @@ function createOAuthRouter(ctx) {
|
|
|
2533
2548
|
router.post(
|
|
2534
2549
|
"/token",
|
|
2535
2550
|
cors,
|
|
2551
|
+
requireIndexes,
|
|
2536
2552
|
form,
|
|
2537
2553
|
rateLimit(ctx, "token", clientKey),
|
|
2538
2554
|
w(async (req, res) => {
|
|
@@ -2637,6 +2653,7 @@ function createOAuthRouter(ctx) {
|
|
|
2637
2653
|
);
|
|
2638
2654
|
router.post(
|
|
2639
2655
|
"/consent/:requestId",
|
|
2656
|
+
requireIndexes,
|
|
2640
2657
|
rateLimit(ctx, "consent", ipKey),
|
|
2641
2658
|
w(async (req, res) => {
|
|
2642
2659
|
const user = await requireUser(ctx, req);
|
|
@@ -2738,6 +2755,16 @@ function corsMiddleware(ctx) {
|
|
|
2738
2755
|
};
|
|
2739
2756
|
}
|
|
2740
2757
|
|
|
2758
|
+
// src/server/vendors.ts
|
|
2759
|
+
var CLAUDE_CONNECTOR_REDIRECT_URI = "https://claude.ai/api/mcp/auth_callback";
|
|
2760
|
+
var CLAUDE_CODE_REDIRECT_URIS = [
|
|
2761
|
+
"http://localhost/callback",
|
|
2762
|
+
"http://127.0.0.1/callback"
|
|
2763
|
+
];
|
|
2764
|
+
var CHATGPT_LEGACY_REDIRECT_URI = "https://chatgpt.com/connector_platform_oauth_redirect";
|
|
2765
|
+
var CHATGPT_CONNECTOR_REDIRECT_URI_PATTERN = "https://chatgpt.com/connector/oauth/{callback_id}";
|
|
2766
|
+
var CIMD_ALLOWED_HOSTS = ["claude.ai", "chatgpt.com"];
|
|
2767
|
+
|
|
2741
2768
|
// src/server/index.ts
|
|
2742
2769
|
function createOAuthHost(config) {
|
|
2743
2770
|
const ctx = resolveConfig(config);
|
|
@@ -2761,13 +2788,30 @@ function createOAuthHost(config) {
|
|
|
2761
2788
|
* stops one user holding two live grants for the same client, and mongoose
|
|
2762
2789
|
* builds indexes in the background — a cold database will happily serve
|
|
2763
2790
|
* the write that violates it first. See standards/traps.md #3.
|
|
2791
|
+
*
|
|
2792
|
+
* Resolving this is also what flips `ready` and un-gates `/authorize`,
|
|
2793
|
+
* `POST /consent/:requestId` and `POST /token`.
|
|
2764
2794
|
*/
|
|
2765
|
-
syncIndexes: () =>
|
|
2795
|
+
syncIndexes: () => ctx.syncIndexes(),
|
|
2796
|
+
/**
|
|
2797
|
+
* Has `syncIndexes()` resolved?
|
|
2798
|
+
*
|
|
2799
|
+
* A boolean, not a promise, and the difference is the failure mode. A
|
|
2800
|
+
* promise would have to exist from construction, so a host that never calls
|
|
2801
|
+
* `syncIndexes()` would await it forever — a boot-order mistake turning into
|
|
2802
|
+
* an unexplained hang with no message. A boolean is plainly `false`, cannot
|
|
2803
|
+
* be awaited by accident, and is backed by three routes that say what is
|
|
2804
|
+
* wrong by name. Gate a mount on it, or simply
|
|
2805
|
+
* `await oauth.syncIndexes()` first, which is the same thing said directly.
|
|
2806
|
+
*/
|
|
2807
|
+
get ready() {
|
|
2808
|
+
return ctx.indexes.ready;
|
|
2809
|
+
},
|
|
2766
2810
|
/** Escape hatch. Prefer the APIs above; these carry no invariants. */
|
|
2767
2811
|
models: ctx.models
|
|
2768
2812
|
};
|
|
2769
2813
|
}
|
|
2770
2814
|
|
|
2771
|
-
export { OAuthError, RedirectableAuthError, UnredirectableError, createModels, createOAuthHost, createUserAdapter, defaultResolveUser, syncModelIndexes };
|
|
2815
|
+
export { CHATGPT_CONNECTOR_REDIRECT_URI_PATTERN, CHATGPT_LEGACY_REDIRECT_URI, CIMD_ALLOWED_HOSTS, CLAUDE_CODE_REDIRECT_URIS, CLAUDE_CONNECTOR_REDIRECT_URI, OAuthError, RedirectableAuthError, UnredirectableError, createModels, createOAuthHost, createUserAdapter, defaultResolveUser, syncModelIndexes };
|
|
2772
2816
|
//# sourceMappingURL=index.js.map
|
|
2773
2817
|
//# sourceMappingURL=index.js.map
|