@keycardai/express 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +77 -0
- package/dist/cjs/bearerAuth.d.ts +76 -0
- package/dist/cjs/bearerAuth.d.ts.map +1 -0
- package/dist/cjs/bearerAuth.js +123 -0
- package/dist/cjs/bearerAuth.js.map +1 -0
- package/dist/cjs/grant.d.ts +46 -0
- package/dist/cjs/grant.d.ts.map +1 -0
- package/dist/cjs/grant.js +99 -0
- package/dist/cjs/grant.js.map +1 -0
- package/dist/cjs/index.d.ts +9 -0
- package/dist/cjs/index.d.ts.map +1 -0
- package/dist/cjs/index.js +12 -0
- package/dist/cjs/index.js.map +1 -0
- package/dist/cjs/middleware.d.ts +54 -0
- package/dist/cjs/middleware.d.ts.map +1 -0
- package/dist/cjs/middleware.js +49 -0
- package/dist/cjs/middleware.js.map +1 -0
- package/dist/cjs/package.json +1 -0
- package/dist/cjs/wellKnown.d.ts +48 -0
- package/dist/cjs/wellKnown.d.ts.map +1 -0
- package/dist/cjs/wellKnown.js +73 -0
- package/dist/cjs/wellKnown.js.map +1 -0
- package/dist/esm/bearerAuth.d.ts +76 -0
- package/dist/esm/bearerAuth.d.ts.map +1 -0
- package/dist/esm/bearerAuth.js +120 -0
- package/dist/esm/bearerAuth.js.map +1 -0
- package/dist/esm/grant.d.ts +46 -0
- package/dist/esm/grant.d.ts.map +1 -0
- package/dist/esm/grant.js +96 -0
- package/dist/esm/grant.js.map +1 -0
- package/dist/esm/index.d.ts +9 -0
- package/dist/esm/index.d.ts.map +1 -0
- package/dist/esm/index.js +5 -0
- package/dist/esm/index.js.map +1 -0
- package/dist/esm/middleware.d.ts +54 -0
- package/dist/esm/middleware.d.ts.map +1 -0
- package/dist/esm/middleware.js +46 -0
- package/dist/esm/middleware.js.map +1 -0
- package/dist/esm/package.json +1 -0
- package/dist/esm/wellKnown.d.ts +48 -0
- package/dist/esm/wellKnown.d.ts.map +1 -0
- package/dist/esm/wellKnown.js +70 -0
- package/dist/esm/wellKnown.js.map +1 -0
- package/package.json +53 -0
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
import { Router } from "express";
|
|
2
|
+
/**
|
|
3
|
+
* Returns an Express Router that serves the two OAuth discovery endpoints
|
|
4
|
+
* required by RFC 9728 and RFC 8414:
|
|
5
|
+
*
|
|
6
|
+
* - `GET /.well-known/oauth-protected-resource` (RFC 9728 §2)
|
|
7
|
+
* - `GET /.well-known/oauth-authorization-server` (RFC 8414 §3, proxied)
|
|
8
|
+
*
|
|
9
|
+
* Mount it at the application root:
|
|
10
|
+
* ```ts
|
|
11
|
+
* import express from "express";
|
|
12
|
+
* import { keycardMetadataRouter } from "@keycardai/express";
|
|
13
|
+
*
|
|
14
|
+
* const app = express();
|
|
15
|
+
* app.use(keycardMetadataRouter({ issuer: "https://zone.keycard.cloud" }));
|
|
16
|
+
* ```
|
|
17
|
+
*
|
|
18
|
+
* These paths must remain publicly accessible (no bearer auth) per their
|
|
19
|
+
* respective specs. Per the security guidance in
|
|
20
|
+
* `@keycardai/starlette` and the feedback_specific_path_bypass rule:
|
|
21
|
+
* only bypass auth for these exact paths, never a broad `/.well-known/` prefix.
|
|
22
|
+
*/
|
|
23
|
+
export function keycardMetadataRouter(options) {
|
|
24
|
+
const router = Router();
|
|
25
|
+
router.get("/.well-known/oauth-protected-resource", protectedResourceHandler(options));
|
|
26
|
+
router.get("/.well-known/oauth-authorization-server", authorizationServerHandler(options.issuer, options.asMetadataTimeoutMs ?? 10_000));
|
|
27
|
+
return router;
|
|
28
|
+
}
|
|
29
|
+
function protectedResourceHandler(options) {
|
|
30
|
+
return (req, res) => {
|
|
31
|
+
const resource = `${req.protocol}://${req.host}`;
|
|
32
|
+
const metadata = {
|
|
33
|
+
resource,
|
|
34
|
+
authorization_servers: [options.issuer],
|
|
35
|
+
};
|
|
36
|
+
if (options.resourceName)
|
|
37
|
+
metadata.resource_name = options.resourceName;
|
|
38
|
+
if (options.scopesSupported)
|
|
39
|
+
metadata.scopes_supported = [...options.scopesSupported];
|
|
40
|
+
if (options.resourceDocumentation)
|
|
41
|
+
metadata.resource_documentation = options.resourceDocumentation;
|
|
42
|
+
res.set("Access-Control-Allow-Origin", "*");
|
|
43
|
+
res.status(200).json(metadata);
|
|
44
|
+
};
|
|
45
|
+
}
|
|
46
|
+
function authorizationServerHandler(issuer, timeoutMs) {
|
|
47
|
+
return async (req, res, next) => {
|
|
48
|
+
try {
|
|
49
|
+
const upstream = await fetch(`${issuer}/.well-known/oauth-authorization-server`, { signal: AbortSignal.timeout(timeoutMs) });
|
|
50
|
+
if (!upstream.ok) {
|
|
51
|
+
res.status(502).json({ error: "Failed to fetch AS metadata from issuer" });
|
|
52
|
+
return;
|
|
53
|
+
}
|
|
54
|
+
const metadata = await upstream.json();
|
|
55
|
+
// Rewrite authorization_endpoint to include a `resource` param pointing
|
|
56
|
+
// at this server's origin so the AS knows which resource is being accessed.
|
|
57
|
+
if (typeof metadata.authorization_endpoint === "string") {
|
|
58
|
+
const authUrl = new URL(metadata.authorization_endpoint);
|
|
59
|
+
authUrl.searchParams.set("resource", `${req.protocol}://${req.host}`);
|
|
60
|
+
metadata.authorization_endpoint = authUrl.toString();
|
|
61
|
+
}
|
|
62
|
+
res.set("Access-Control-Allow-Origin", "*");
|
|
63
|
+
res.status(200).json(metadata);
|
|
64
|
+
}
|
|
65
|
+
catch (e) {
|
|
66
|
+
next(e);
|
|
67
|
+
}
|
|
68
|
+
};
|
|
69
|
+
}
|
|
70
|
+
//# sourceMappingURL=wellKnown.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"wellKnown.js","sourceRoot":"","sources":["../../src/wellKnown.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,MAAM,SAAS,CAAC;AA4BjC;;;;;;;;;;;;;;;;;;;;GAoBG;AACH,MAAM,UAAU,qBAAqB,CAAC,OAA6B;IACjE,MAAM,MAAM,GAAG,MAAM,EAAE,CAAC;IAExB,MAAM,CAAC,GAAG,CACR,uCAAuC,EACvC,wBAAwB,CAAC,OAAO,CAAC,CAClC,CAAC;IAEF,MAAM,CAAC,GAAG,CACR,yCAAyC,EACzC,0BAA0B,CAAC,OAAO,CAAC,MAAM,EAAE,OAAO,CAAC,mBAAmB,IAAI,MAAM,CAAC,CAClF,CAAC;IAEF,OAAO,MAAM,CAAC;AAChB,CAAC;AAED,SAAS,wBAAwB,CAAC,OAA6B;IAC7D,OAAO,CAAC,GAAG,EAAE,GAAG,EAAE,EAAE;QAClB,MAAM,QAAQ,GAAG,GAAG,GAAG,CAAC,QAAQ,MAAM,GAAG,CAAC,IAAI,EAAE,CAAC;QACjD,MAAM,QAAQ,GAA4B;YACxC,QAAQ;YACR,qBAAqB,EAAE,CAAC,OAAO,CAAC,MAAM,CAAC;SACxC,CAAC;QACF,IAAI,OAAO,CAAC,YAAY;YAAE,QAAQ,CAAC,aAAa,GAAG,OAAO,CAAC,YAAY,CAAC;QACxE,IAAI,OAAO,CAAC,eAAe;YAAE,QAAQ,CAAC,gBAAgB,GAAG,CAAC,GAAG,OAAO,CAAC,eAAe,CAAC,CAAC;QACtF,IAAI,OAAO,CAAC,qBAAqB;YAAE,QAAQ,CAAC,sBAAsB,GAAG,OAAO,CAAC,qBAAqB,CAAC;QAEnG,GAAG,CAAC,GAAG,CAAC,6BAA6B,EAAE,GAAG,CAAC,CAAC;QAC5C,GAAG,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC;IACjC,CAAC,CAAC;AACJ,CAAC;AAED,SAAS,0BAA0B,CAAC,MAAc,EAAE,SAAiB;IACnE,OAAO,KAAK,EAAE,GAAG,EAAE,GAAG,EAAE,IAAI,EAAE,EAAE;QAC9B,IAAI,CAAC;YACH,MAAM,QAAQ,GAAG,MAAM,KAAK,CAC1B,GAAG,MAAM,yCAAyC,EAClD,EAAE,MAAM,EAAE,WAAW,CAAC,OAAO,CAAC,SAAS,CAAC,EAAE,CAC3C,CAAC;YACF,IAAI,CAAC,QAAQ,CAAC,EAAE,EAAE,CAAC;gBACjB,GAAG,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,EAAE,KAAK,EAAE,yCAAyC,EAAE,CAAC,CAAC;gBAC3E,OAAO;YACT,CAAC;YACD,MAAM,QAAQ,GAAG,MAAM,QAAQ,CAAC,IAAI,EAA6B,CAAC;YAElE,wEAAwE;YACxE,4EAA4E;YAC5E,IAAI,OAAO,QAAQ,CAAC,sBAAsB,KAAK,QAAQ,EAAE,CAAC;gBACxD,MAAM,OAAO,GAAG,IAAI,GAAG,CAAC,QAAQ,CAAC,sBAAsB,CAAC,CAAC;gBACzD,OAAO,CAAC,YAAY,CAAC,GAAG,CAAC,UAAU,EAAE,GAAG,GAAG,CAAC,QAAQ,MAAM,GAAG,CAAC,IAAI,EAAE,CAAC,CAAC;gBACtE,QAAQ,CAAC,sBAAsB,GAAG,OAAO,CAAC,QAAQ,EAAE,CAAC;YACvD,CAAC;YAED,GAAG,CAAC,GAAG,CAAC,6BAA6B,EAAE,GAAG,CAAC,CAAC;YAC5C,GAAG,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC;QACjC,CAAC;QAAC,OAAO,CAAC,EAAE,CAAC;YACX,IAAI,CAAC,CAAC,CAAC,CAAC;QACV,CAAC;IACH,CAAC,CAAC;AACJ,CAAC"}
|
package/package.json
ADDED
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@keycardai/express",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"description": "[Preview] Keycard auth middleware for Express: bearer token validation, RFC 6750 challenges, delegated token exchange, and OAuth discovery routes",
|
|
5
|
+
"license": "MIT",
|
|
6
|
+
"repository": {
|
|
7
|
+
"type": "git",
|
|
8
|
+
"url": "git+https://github.com/keycardai/typescript-sdk.git",
|
|
9
|
+
"directory": "packages/express"
|
|
10
|
+
},
|
|
11
|
+
"type": "module",
|
|
12
|
+
"exports": {
|
|
13
|
+
".": {
|
|
14
|
+
"import": "./dist/esm/index.js",
|
|
15
|
+
"require": "./dist/cjs/index.js",
|
|
16
|
+
"types": "./dist/esm/index.d.ts"
|
|
17
|
+
}
|
|
18
|
+
},
|
|
19
|
+
"files": [
|
|
20
|
+
"dist"
|
|
21
|
+
],
|
|
22
|
+
"typesVersions": {
|
|
23
|
+
"*": {
|
|
24
|
+
"*": [
|
|
25
|
+
"./dist/esm/*"
|
|
26
|
+
]
|
|
27
|
+
}
|
|
28
|
+
},
|
|
29
|
+
"scripts": {
|
|
30
|
+
"build": "pnpm run build:esm && pnpm run build:cjs",
|
|
31
|
+
"build:esm": "tsc -p tsconfig.prod.json && echo '{\"type\": \"module\"}' > dist/esm/package.json",
|
|
32
|
+
"build:cjs": "tsc -p tsconfig.cjs.json && echo '{\"type\": \"commonjs\"}' > dist/cjs/package.json",
|
|
33
|
+
"test": "NODE_OPTIONS='--experimental-vm-modules' jest",
|
|
34
|
+
"typecheck": "tsc --noEmit",
|
|
35
|
+
"clean": "rm -rf dist"
|
|
36
|
+
},
|
|
37
|
+
"dependencies": {
|
|
38
|
+
"@keycardai/oauth": "workspace:*"
|
|
39
|
+
},
|
|
40
|
+
"peerDependencies": {
|
|
41
|
+
"express": ">=4.0.0"
|
|
42
|
+
},
|
|
43
|
+
"devDependencies": {
|
|
44
|
+
"@jest/globals": "^30.0.4",
|
|
45
|
+
"@types/express": "^5.0.3",
|
|
46
|
+
"@types/supertest": "^6.0.3",
|
|
47
|
+
"express": "^5.0.0",
|
|
48
|
+
"jest": "^30.0.4",
|
|
49
|
+
"supertest": "^7.1.1",
|
|
50
|
+
"ts-jest": "^29.4.0",
|
|
51
|
+
"typescript": "^5.8.3"
|
|
52
|
+
}
|
|
53
|
+
}
|