@atlasauth/pca-next 0.0.0-stage → 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/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Atlas Authorization
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md CHANGED
@@ -1,3 +1,53 @@
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 (App Router) helper for Proof-Carrying Authority (PCA). `withPCA` wraps a Route Handler so the inbound PCActn is verified with the resource-server guard from `@atlasauth/pca` before your handler runs; otherwise it returns a 401/403 JSON response with a `WWW-Authenticate` challenge. Verification is default-deny.
4
+
5
+ ## Install
6
+
7
+ ```sh
8
+ npm i @atlasauth/pca-next @atlasauth/pca
9
+ npm i next # optional peer dependency (^14 || ^15)
10
+ ```
11
+
12
+ ## Usage
13
+
14
+ ```ts
15
+ // app/refunds/route.ts
16
+ import { withPCA } from '@atlasauth/pca-next';
17
+ import { memoryPcaStore } from '@atlasauth/pca';
18
+
19
+ export const POST = withPCA(
20
+ {
21
+ audience: 'ins_acme', // this resource server's id; the PCActn's signed `aud` must match
22
+ resolveGrant: async (ref) => grants.get(ref) ?? null, // look up the Root Intent Grant by grant_ref
23
+ budgetStore: memoryPcaStore(), // replay counter store (use a durable one in production)
24
+ hooks: { revocation: async () => ({ enforced: true, ok: !(await isRevoked()) }) }, // revocation checker
25
+ context: async (req, pcactn) => ({ // facts only the resource server can vouch for
26
+ params: { amount: 20, currency: 'usd' },
27
+ plan: authorizedPlanNodes, // your copy of the principal-authorized plan
28
+ planAuthorized: true,
29
+ budget: { B: 500, tau: 0 },
30
+ risk: { blastRadius: 0.04 }, // risk inputs you can vouch for (missing ones fail closed to worst case)
31
+ }),
32
+ },
33
+ async (req, { pca }) => {
34
+ const { verdict, pcactn } = pca; // handler only runs for a valid PCActn
35
+ return Response.json({ ok: true });
36
+ },
37
+ );
38
+ ```
39
+
40
+ The client sends the PCActn as a `PCA-Action: <base64url>` header (see `pcaHeaders` in `@atlasauth/pca`) or as a JSON body `{ pcactn }`; the default extractor reads both. The wrapper reads a clone of the request body, so your handler can still read it. By default a deployment must supply `budgetStore`, a `hooks.revocation` checker, and a `context()` returning the server's own `plan` and `planAuthorized: true`; otherwise requests are denied. `insecureAllowUnenforced: true` relaxes this for local development only.
41
+
42
+ ## API
43
+
44
+ - `withPCA(options, handler)` - returns `(req: Request) => Promise<Response>`. Options extend `RequirePcaOptions` from `@atlasauth/pca`, plus `onDeny(result, req)` to customize the error response.
45
+ - Re-exports `requirePCA`, `defaultExtract`, `memoryPcaStore`.
46
+
47
+ ## Status
48
+
49
+ This package only wires the guard into Next.js route handlers; all verification logic lives in `@atlasauth/pca`. PCA cryptography has not been independently audited.
50
+
51
+ ## License
52
+
53
+ MIT - see LICENSE
@@ -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/pca` (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/pca';
20
+ import type { PcaGuardResult, RequirePcaOptions, PcaStateStore } from '@atlasauth/pca';
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/pca` (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 pca_1 = require("@atlasauth/pca");
24
+ Object.defineProperty(exports, "requirePCA", { enumerable: true, get: function () { return pca_1.requirePCA; } });
25
+ Object.defineProperty(exports, "defaultExtract", { enumerable: true, get: function () { return pca_1.defaultExtract; } });
26
+ Object.defineProperty(exports, "memoryPcaStore", { enumerable: true, get: function () { return pca_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, pca_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,wCAA4E;AA0CnE,2FA1CA,gBAAU,OA0CA;AAAE,+FA1CA,oBAAc,OA0CA;AAAE,+FA1CA,oBAAc,OA0CA;AAxBnD,2EAA2E;AAC3E,SAAgB,OAAO,CAAC,OAAuB,EAAE,OAAwB;IACvE,MAAM,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC;IAC9B,MAAM,KAAK,GAAG,IAAA,gBAAU,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,64 @@
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.2.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
+ "keywords": [
6
+ "next.js",
7
+ "route handler",
8
+ "middleware",
9
+ "agent authorization",
10
+ "proof-carrying authority",
11
+ "pca",
12
+ "ai agents"
13
+ ],
14
+ "license": "MIT",
15
+ "homepage": "https://github.com/Atlas-Authorization/pca#readme",
16
+ "bugs": {
17
+ "url": "https://github.com/Atlas-Authorization/pca/issues"
18
+ },
19
+ "repository": {
20
+ "type": "git",
21
+ "url": "git+https://github.com/Atlas-Authorization/pca.git",
22
+ "directory": "packages/pca-next"
23
+ },
24
+ "main": "./dist/index.js",
25
+ "types": "./dist/index.d.ts",
26
+ "exports": {
27
+ ".": {
28
+ "types": "./dist/index.d.ts",
29
+ "default": "./dist/index.js"
30
+ },
31
+ "./package.json": "./package.json"
32
+ },
33
+ "dependencies": {
34
+ "@atlasauth/pca": "0.2.0"
35
+ },
36
+ "peerDependencies": {
37
+ "next": "^14 || ^15"
38
+ },
39
+ "peerDependenciesMeta": {
40
+ "next": {
41
+ "optional": true
42
+ }
43
+ },
44
+ "devDependencies": {
45
+ "typescript": "^5.6.3",
46
+ "vitest": "^2.1.4"
47
+ },
48
+ "files": [
49
+ "dist",
50
+ "README.md",
51
+ "LICENSE"
52
+ ],
53
+ "engines": {
54
+ "node": ">=20"
55
+ },
56
+ "publishConfig": {
57
+ "access": "public"
58
+ },
59
+ "scripts": {
60
+ "build": "tsc -p tsconfig.build.json",
61
+ "typecheck": "tsc -p tsconfig.json --noEmit",
62
+ "test": "vitest run"
63
+ }
6
64
  }