@atlasauth/pca-next 0.0.0-stage → 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 CHANGED
@@ -1,3 +1,36 @@
1
- # Temporary Holding Version
1
+ # @atlasauth/pca-next
2
2
 
3
- This version is a temporary placeholder for this package. An operational version to replace this has been submitted for review and is awaiting a staged release.
3
+ Next.js helper for Proof-Carrying Authority: wrap a Route Handler so the inbound PCActn is verified before your handler runs, with a 401/403 response otherwise.
4
+
5
+ ## Install
6
+
7
+ ```sh
8
+ npm i @atlasauth/pca-next
9
+ # peer dependency, install alongside:
10
+ npm i next
11
+ ```
12
+
13
+ `next` (v14 or v15) is an optional peer dependency.
14
+
15
+ ## Usage
16
+
17
+ ```ts
18
+ // app/refunds/route.ts
19
+ import { withPCA } from '@atlasauth/pca-next';
20
+
21
+ export const POST = withPCA(
22
+ {
23
+ audience: 'ins_acme', // this resource server's / instance id the PCActn must name
24
+ resolveGrant, // (ref) => Capability — look up the root grant
25
+ budgetStore, // per-holder replay/budget store
26
+ },
27
+ async (req, { pca }) => {
28
+ const { verdict, pcactn } = pca; // handler only runs on a valid PCActn
29
+ return Response.json({ ok: true });
30
+ },
31
+ );
32
+ ```
33
+
34
+ The client sends the PCActn as `PCA-Action: <base64url>` (see `@atlasauth/pca` `pcaHeaders`) or a JSON body `{ pcactn }` — the default extractor reads both. The wrapper verifies and is default-deny; it is the verifier that decides, not the client's proof.
35
+
36
+ Part of Proof-Carrying Authority — see `@atlasauth/pca`.
@@ -0,0 +1,42 @@
1
+ /**
2
+ * Next.js App-Router helper for Proof-Carrying Authority.
3
+ *
4
+ * export const POST = withPCA(
5
+ * { audience: 'ins_acme', resolveGrant, budgetStore, hooks, context },
6
+ * async (req, { pca }) => { const { verdict, pcactn } = pca; return Response.json({ ok: true }); },
7
+ * );
8
+ *
9
+ * It wraps a Route Handler so the inbound PCActn is verified with the framework-agnostic `requirePCA` guard
10
+ * from `@atlasauth/backend` (default-deny: a required check that is unenforced DENIES) before your handler
11
+ * runs. On success it calls your handler with `{ pca: { verdict, pcactn } }`; on failure it returns a 401/403
12
+ * JSON response with a WWW-Authenticate challenge. The client sends the PCActn as `PCA-Action: <base64url>`
13
+ * (see `@atlasauth/pca` `pcaHeaders`) or a JSON body `{ pcactn }`; that is exactly what the default extractor
14
+ * reads, so no wiring is needed.
15
+ *
16
+ * `next` is an OPTIONAL peer dependency and is never imported — the handler takes the web `Request` and returns
17
+ * a web `Response`, which is exactly what an App-Router Route Handler is.
18
+ */
19
+ import { requirePCA, defaultExtract, memoryPcaStore } from '@atlasauth/backend';
20
+ import type { PcaGuardResult, RequirePcaOptions, PcaStateStore } from '@atlasauth/backend';
21
+ import type { PCActn } from '@atlasauth/pca';
22
+ /** The verdict + PCActn handed to the wrapped handler on success. */
23
+ export interface PcaAttachment {
24
+ verdict: Extract<PcaGuardResult, {
25
+ ok: true;
26
+ }>['verdict'];
27
+ pcactn: PCActn;
28
+ }
29
+ /** A Next.js App-Router Route Handler that receives the verified PCActn in its context. */
30
+ export type PcaRouteHandler = (req: Request, ctx: {
31
+ pca: PcaAttachment;
32
+ }) => Response | Promise<Response>;
33
+ export interface PcaNextOptions extends RequirePcaOptions {
34
+ /** Override the 401/403 response (otherwise a JSON error + WWW-Authenticate is returned). */
35
+ onDeny?: (result: Extract<PcaGuardResult, {
36
+ ok: false;
37
+ }>, req: Request) => Response | Promise<Response>;
38
+ }
39
+ /** Wrap an App-Router Route Handler so it only runs for a valid PCActn. */
40
+ export declare function withPCA(options: PcaNextOptions, handler: PcaRouteHandler): (req: Request) => Promise<Response>;
41
+ export { requirePCA, defaultExtract, memoryPcaStore };
42
+ export type { PcaGuardResult, RequirePcaOptions, PcaStateStore };
package/dist/index.js ADDED
@@ -0,0 +1,51 @@
1
+ "use strict";
2
+ /**
3
+ * Next.js App-Router helper for Proof-Carrying Authority.
4
+ *
5
+ * export const POST = withPCA(
6
+ * { audience: 'ins_acme', resolveGrant, budgetStore, hooks, context },
7
+ * async (req, { pca }) => { const { verdict, pcactn } = pca; return Response.json({ ok: true }); },
8
+ * );
9
+ *
10
+ * It wraps a Route Handler so the inbound PCActn is verified with the framework-agnostic `requirePCA` guard
11
+ * from `@atlasauth/backend` (default-deny: a required check that is unenforced DENIES) before your handler
12
+ * runs. On success it calls your handler with `{ pca: { verdict, pcactn } }`; on failure it returns a 401/403
13
+ * JSON response with a WWW-Authenticate challenge. The client sends the PCActn as `PCA-Action: <base64url>`
14
+ * (see `@atlasauth/pca` `pcaHeaders`) or a JSON body `{ pcactn }`; that is exactly what the default extractor
15
+ * reads, so no wiring is needed.
16
+ *
17
+ * `next` is an OPTIONAL peer dependency and is never imported — the handler takes the web `Request` and returns
18
+ * a web `Response`, which is exactly what an App-Router Route Handler is.
19
+ */
20
+ Object.defineProperty(exports, "__esModule", { value: true });
21
+ exports.memoryPcaStore = exports.defaultExtract = exports.requirePCA = void 0;
22
+ exports.withPCA = withPCA;
23
+ const backend_1 = require("@atlasauth/backend");
24
+ Object.defineProperty(exports, "requirePCA", { enumerable: true, get: function () { return backend_1.requirePCA; } });
25
+ Object.defineProperty(exports, "defaultExtract", { enumerable: true, get: function () { return backend_1.defaultExtract; } });
26
+ Object.defineProperty(exports, "memoryPcaStore", { enumerable: true, get: function () { return backend_1.memoryPcaStore; } });
27
+ /** Wrap an App-Router Route Handler so it only runs for a valid PCActn. */
28
+ function withPCA(options, handler) {
29
+ const onDeny = options.onDeny;
30
+ const guard = (0, backend_1.requirePCA)(options);
31
+ return async (req) => {
32
+ const like = {
33
+ headers: { get: (n) => req.headers.get(n) },
34
+ body: await req.clone().json().catch(() => undefined),
35
+ };
36
+ const result = await guard(like);
37
+ if (result.ok) {
38
+ return handler(req, { pca: { verdict: result.verdict, pcactn: result.pcactn } });
39
+ }
40
+ if (onDeny)
41
+ return onDeny(result, req);
42
+ return new Response(JSON.stringify({ error: result.verdict.reasons?.[0] ?? 'forbidden', verdict: result.verdict }), {
43
+ status: result.status,
44
+ headers: {
45
+ 'content-type': 'application/json',
46
+ ...(result.wwwAuthenticate ? { 'WWW-Authenticate': result.wwwAuthenticate } : {}),
47
+ },
48
+ });
49
+ };
50
+ }
51
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";AAAA;;;;;;;;;;;;;;;;;GAiBG;;;AAqBH,0BAqBC;AAxCD,gDAAgF;AA0CvE,2FA1CA,oBAAU,OA0CA;AAAE,+FA1CA,wBAAc,OA0CA;AAAE,+FA1CA,wBAAc,OA0CA;AAxBnD,2EAA2E;AAC3E,SAAgB,OAAO,CAAC,OAAuB,EAAE,OAAwB;IACvE,MAAM,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC;IAC9B,MAAM,KAAK,GAAG,IAAA,oBAAU,EAAC,OAAO,CAAC,CAAC;IAClC,OAAO,KAAK,EAAE,GAAY,EAAqB,EAAE;QAC/C,MAAM,IAAI,GAAmB;YAC3B,OAAO,EAAE,EAAE,GAAG,EAAE,CAAC,CAAS,EAAE,EAAE,CAAC,GAAG,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE;YACnD,IAAI,EAAE,MAAM,GAAG,CAAC,KAAK,EAAE,CAAC,IAAI,EAAE,CAAC,KAAK,CAAC,GAAG,EAAE,CAAC,SAAS,CAAC;SACtD,CAAC;QACF,MAAM,MAAM,GAAmB,MAAM,KAAK,CAAC,IAAI,CAAC,CAAC;QACjD,IAAI,MAAM,CAAC,EAAE,EAAE,CAAC;YACd,OAAO,OAAO,CAAC,GAAG,EAAE,EAAE,GAAG,EAAE,EAAE,OAAO,EAAE,MAAM,CAAC,OAAO,EAAE,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,EAAE,CAAC,CAAC;QACnF,CAAC;QACD,IAAI,MAAM;YAAE,OAAO,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,CAAC;QACvC,OAAO,IAAI,QAAQ,CAAC,IAAI,CAAC,SAAS,CAAC,EAAE,KAAK,EAAE,MAAM,CAAC,OAAO,CAAC,OAAO,EAAE,CAAC,CAAC,CAAC,IAAI,WAAW,EAAE,OAAO,EAAE,MAAM,CAAC,OAAO,EAAE,CAAC,EAAE;YAClH,MAAM,EAAE,MAAM,CAAC,MAAM;YACrB,OAAO,EAAE;gBACP,cAAc,EAAE,kBAAkB;gBAClC,GAAG,CAAC,MAAM,CAAC,eAAe,CAAC,CAAC,CAAC,EAAE,kBAAkB,EAAE,MAAM,CAAC,eAAe,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;aAClF;SACF,CAAC,CAAC;IACL,CAAC,CAAC;AACJ,CAAC"}
package/package.json CHANGED
@@ -1,6 +1,42 @@
1
1
  {
2
2
  "name": "@atlasauth/pca-next",
3
- "version": "0.0.0-stage",
4
- "stub": true,
5
- "description": "Temporary package placeholder for staged publishing"
3
+ "version": "0.1.0",
4
+ "description": "Next.js helper for Proof-Carrying Authority: wrap a Route Handler so the inbound PCActn is verified before your handler runs, with a 401/403 response otherwise.",
5
+ "main": "./dist/index.js",
6
+ "types": "./dist/index.d.ts",
7
+ "exports": {
8
+ ".": {
9
+ "types": "./dist/index.d.ts",
10
+ "default": "./dist/index.js"
11
+ },
12
+ "./package.json": "./package.json"
13
+ },
14
+ "dependencies": {
15
+ "@atlasauth/pca": "0.1.0",
16
+ "@atlasauth/backend": "0.3.0"
17
+ },
18
+ "peerDependencies": {
19
+ "next": "^14 || ^15"
20
+ },
21
+ "peerDependenciesMeta": {
22
+ "next": {
23
+ "optional": true
24
+ }
25
+ },
26
+ "devDependencies": {
27
+ "typescript": "^5.6.3",
28
+ "vitest": "^2.1.4"
29
+ },
30
+ "files": [
31
+ "dist",
32
+ "README.md"
33
+ ],
34
+ "publishConfig": {
35
+ "access": "public"
36
+ },
37
+ "scripts": {
38
+ "build": "tsc -p tsconfig.build.json",
39
+ "typecheck": "tsc -p tsconfig.json --noEmit",
40
+ "test": "vitest run"
41
+ }
6
42
  }