{"_id":"@adastracomputing/aer-resource-node","_rev":"4-b797ebfb90a5a142ea0ce9bfeb7bb59c","name":"@adastracomputing/aer-resource-node","dist-tags":{"latest":"0.1.2"},"versions":{"0.1.0":{"name":"@adastracomputing/aer-resource-node","version":"0.1.0","author":{"name":"Ad Astra Computing"},"license":"Apache-2.0","_id":"@adastracomputing/aer-resource-node@0.1.0","maintainers":[{"name":"adastracomputing","email":"npm@adastracomputing.com"}],"homepage":"https://aer.adastra.computer","dist":{"shasum":"ee463829792884bf6baef357d764702cc42e6940","tarball":"https://registry.npmjs.org/@adastracomputing/aer-resource-node/-/aer-resource-node-0.1.0.tgz","fileCount":15,"integrity":"sha512-yHCTrZapjeI0Hqv7FKeZ6698VczMk54GqbjBkXWW+BhEtu4vuDX7CJYQ4cf+2gpDkB74o17ysgzMJ9/0c05N2Q==","signatures":[{"sig":"MEUCIAwQXYlVGcQcLI6aJ4ZHbfXBr3Q8pc6Mn4HNEyfC+xmDAiEArrzSqa1WFlKUGdyHJ9+Ty41tY79rGZT/ZpPyPwsOWao=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":70807},"main":"./dist/index.js","type":"module","_from":"file:adastracomputing-aer-resource-node-0.1.0.tgz","types":"./dist/index.d.ts","exports":{".":{"types":"./dist/index.d.ts","import":"./dist/index.js"},"./hono":{"types":"./dist/hono.d.ts","import":"./dist/hono.js"},"./express":{"types":"./dist/express.d.ts","import":"./dist/express.js"}},"scripts":{"lint":"eslint src","test":"vitest run","build":"tsc -p tsconfig.json","typecheck":"tsc --noEmit -p tsconfig.json"},"_npmUser":{"name":"adastracomputing","email":"npm@adastracomputing.com"},"_resolved":"/tmp/a69a50432769a4eb87c64a1fdc707383/adastracomputing-aer-resource-node-0.1.0.tgz","_integrity":"sha512-yHCTrZapjeI0Hqv7FKeZ6698VczMk54GqbjBkXWW+BhEtu4vuDX7CJYQ4cf+2gpDkB74o17ysgzMJ9/0c05N2Q==","_npmVersion":"11.12.1","description":"Verify AER Attestation tokens at a protected resource / MCP server — offline against cached JWKS, fail-closed.","directories":{},"_nodeVersion":"24.15.0","dependencies":{},"publishConfig":{"access":"public"},"_hasShrinkwrap":false,"devDependencies":{"hono":"^4.12.25","vitest":"^2.1.0","typescript":"^5.8.0","@types/node":"^20.14.0","@types/express":"^5.0.0","@aer/aer-generator":"0.1.0"},"peerDependencies":{"hono":"*","express":"*"},"peerDependenciesMeta":{"hono":{"optional":true},"express":{"optional":true}},"_npmOperationalInternal":{"tmp":"tmp/aer-resource-node_0.1.0_1783730811337_0.7898882892349632","host":"s3://npm-registry-packages-npm-production"}},"0.1.1":{"name":"@adastracomputing/aer-resource-node","version":"0.1.1","keywords":["aer","attestation","verification","jwks","mcp","zero-trust"],"author":{"name":"Ad Astra Computing"},"license":"Apache-2.0","_id":"@adastracomputing/aer-resource-node@0.1.1","maintainers":[{"name":"adastra-computing","email":"npm@adastracomputing.com"}],"homepage":"https://aer.run","bugs":{"url":"https://github.com/Ad-Astra-Computing/aer/issues"},"dist":{"shasum":"27fc95d144a260fccca9f75d2e822e9bf5191ac6","tarball":"https://registry.npmjs.org/@adastracomputing/aer-resource-node/-/aer-resource-node-0.1.1.tgz","fileCount":10,"integrity":"sha512-Z+0coAahaGa+P7prdoG2FtGT5jDwr6a+33xVsRMZZ/o+cjPO0htttYzzLrEyeJeX1FSM8dYFyPqKCEp3PuaDXw==","signatures":[{"sig":"MEUCIAJT43Y3ZPjv1TtzlqeUP7nwoY4PQthadDhxpi69DHlQAiEAt8xTtLCgc0EMhS5qjHLfCzJdsk1nE8S4lOs+izY/atg=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":49650},"main":"./dist/index.js","type":"module","_from":"file:adastracomputing-aer-resource-node-0.1.1.tgz","types":"./dist/index.d.ts","engines":{"node":">=20"},"exports":{".":{"types":"./dist/index.d.ts","import":"./dist/index.js"},"./hono":{"types":"./dist/hono.d.ts","import":"./dist/hono.js"},"./express":{"types":"./dist/express.d.ts","import":"./dist/express.js"}},"private":false,"scripts":{"lint":"eslint src","test":"vitest run","build":"tsc -p tsconfig.json","typecheck":"tsc --noEmit -p tsconfig.json"},"_npmUser":{"name":"adastra-computing","email":"npm@adastracomputing.com"},"_resolved":"/tmp/0f4ec060b4c3f0f92d95f0ec7ef1f06f/adastracomputing-aer-resource-node-0.1.1.tgz","_integrity":"sha512-Z+0coAahaGa+P7prdoG2FtGT5jDwr6a+33xVsRMZZ/o+cjPO0htttYzzLrEyeJeX1FSM8dYFyPqKCEp3PuaDXw==","repository":{"url":"git+https://github.com/Ad-Astra-Computing/aer.git","type":"git","directory":"packages/aer-resource-node"},"_npmVersion":"11.13.0","description":"Verify AER Attestation tokens at a protected resource or MCP server, offline against cached JWKS, fail-closed.","directories":{},"_nodeVersion":"24.16.0","dependencies":{},"publishConfig":{"access":"public"},"_hasShrinkwrap":false,"devDependencies":{"hono":"^4.12.25","vitest":"^2.1.0","typescript":"^5.8.0","@types/node":"^20.14.0","@types/express":"^5.0.0","@aer/aer-generator":"0.1.0"},"peerDependencies":{"hono":"*","express":"*"},"peerDependenciesMeta":{"hono":{"optional":true},"express":{"optional":true}},"_npmOperationalInternal":{"tmp":"tmp/aer-resource-node_0.1.1_1785105545576_0.6945365700278399","host":"s3://npm-registry-packages-npm-production"}},"0.1.2":{"name":"@adastracomputing/aer-resource-node","version":"0.1.2","description":"Verify AER Attestation tokens at a protected resource or MCP server, offline against cached JWKS, fail-closed.","type":"module","private":false,"main":"./dist/index.js","types":"./dist/index.d.ts","exports":{".":{"types":"./dist/index.d.ts","import":"./dist/index.js"},"./hono":{"types":"./dist/hono.d.ts","import":"./dist/hono.js"},"./express":{"types":"./dist/express.d.ts","import":"./dist/express.js"}},"license":"Apache-2.0","author":"Ad Astra Computing","homepage":"https://aer.run","repository":{"type":"git","url":"https://github.com/Ad-Astra-Computing/aer.git","directory":"packages/aer-resource-node"},"bugs":{"url":"https://github.com/Ad-Astra-Computing/aer/issues"},"keywords":["aer","attestation","verification","jwks","mcp","zero-trust"],"publishConfig":{"access":"public"},"dependencies":{},"peerDependencies":{"hono":"^4","express":"^5"},"peerDependenciesMeta":{"hono":{"optional":true},"express":{"optional":true}},"devDependencies":{"@aer-oss/attestation-test-utils":"0.0.0","@types/express":"^5.0.0","@types/node":"^26.1.2","hono":"^4.13.5","typescript":"^7.0.2","vitest":"^4.1.11"},"engines":{"node":">=20"},"scripts":{"build":"tsc -p tsconfig.json","test":"vitest run","typecheck":"tsc --noEmit -p tsconfig.json","lint":"eslint src"},"_nodeVersion":"24.20.0","_id":"@adastracomputing/aer-resource-node@0.1.2","dist":{"integrity":"sha512-zqMzEjQ78uR4MmR/2AAefkVZ3w7RnTcprmYx903BEBv2Xlvh/MPNGZLhGbsJweyfxN2DUuxVTbg64wRPJuh2SQ==","shasum":"654ba3813a1e966706d0b130fc2640b0a393d969","tarball":"https://registry.npmjs.org/@adastracomputing/aer-resource-node/-/aer-resource-node-0.1.2.tgz","fileCount":10,"unpackedSize":52189,"attestations":{"url":"https://registry.npmjs.org/-/npm/v1/attestations/@adastracomputing%2faer-resource-node@0.1.2","provenance":{"predicateType":"https://slsa.dev/provenance/v1"}},"signatures":[{"keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U","sig":"MEUCIQCjpon7HdwBUnGLFZoZbLlARxHH3ufW06npzBwVEyTUqQIgGp4VG8oWdAVE69Wytl1nhmTANvlKRSIG5MsEbceVd2Y="}]},"_npmUser":{"name":"GitHub Actions","email":"npm-oidc-no-reply@github.com","trustedPublisher":{"id":"github","oidcConfigId":"oidc:e6995d76-aa78-443b-94ea-ad2e6ddadb3e"}},"directories":{},"maintainers":[{"name":"adastra-computing","email":"npm@adastracomputing.com"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages-npm-production","tmp":"tmp/aer-resource-node_0.1.2_1788681628935_0.7774599822085786"},"_hasShrinkwrap":false}},"time":{"created":"2026-07-11T00:46:51.190Z","modified":"2026-09-06T08:00:29.346Z","0.1.0":"2026-07-11T00:46:51.492Z","0.1.1":"2026-07-26T22:39:05.719Z","0.1.2":"2026-09-06T08:00:29.067Z"},"bugs":{"url":"https://github.com/Ad-Astra-Computing/aer/issues"},"author":"Ad Astra Computing","license":"Apache-2.0","homepage":"https://aer.run","keywords":["aer","attestation","verification","jwks","mcp","zero-trust"],"repository":{"type":"git","url":"https://github.com/Ad-Astra-Computing/aer.git","directory":"packages/aer-resource-node"},"description":"Verify AER Attestation tokens at a protected resource or MCP server, offline against cached JWKS, fail-closed.","maintainers":[{"name":"adastra-computing","email":"npm@adastracomputing.com"}],"readme":"# @adastracomputing/aer-resource-node\n\nVerify **AER Attestation** tokens at a protected resource or MCP server. A\nregistered agent (running the AER auto-collector) presents a short-lived token;\nthis library verifies it **offline against cached JWKS, fail-closed**, so\nrequests without a valid token are denied.\n\nZero runtime dependencies. The Hono/Express middleware are optional subpath\nexports.\n\nESM only: use `import`, not `require`. Requires Node 20 or newer.\n\n## Install\n\n```\nnpm install @adastracomputing/aer-resource-node\n```\n\n## Verify a token\n\n```ts\nimport { verifyAttestation, AttestationError } from '@adastracomputing/aer-resource-node';\n\ntry {\n  const claims = await verifyAttestation(token, { audience: 'mcp://payments-prod' });\n  // claims.agent_id / agent_session_id / tenant_id / environment_id …\n} catch (e) {\n  if (e instanceof AttestationError) { /* deny: e.code */ }\n}\n```\n\nDefaults: `issuer` defaults to `https://aer-api.adastra.computer`. This is an\nidentifier, not a URL: it is the exact `iss` string AER mints into every\nattestation token, and it stays fixed even though it does not match the\ncontrol-plane host. Leave it alone unless AER announces an issuer change.\n`jwksUrl` defaults to `https://api.aer.run/.well-known/aer-attestation-jwks.json`,\nthe canonical AER API host. 30s clock tolerance. JWKS is cached (honoring\n`max-age`) and refetched on an unknown `kid`.\n\n## Revocation check (optional introspection)\n\nOffline verify (signature plus short TTL) is the default and needs no network call\npast JWKS. To also honor **revocation** within the token's lifetime, pass\n`introspect`: after the offline check the verifier asks AER whether the token is\nstill active (jti not revoked, session still running).\n\n```ts\nconst claims = await verifyAttestation(token, {\n  audience: 'mcp://payments-prod',\n  introspect: {\n    url: 'https://api.aer.run/v1/attestations/introspect',\n    verifierKey: process.env.AER_VERIFIER_KEY!, // aerv_… ; mint via admin\n    // activeCacheSec: 10,  // cache an active verdict (default 10s, hard max 30s, never past exp)\n    // onUnavailable: 'fail-closed',\n  },\n});\n```\n\nPositive verdicts are cached briefly, so revocation takes effect within\n`activeCacheSec` (default 10s). An `inactive` verdict throws\n`AttestationError('revoked', reason)`.\n\n> **Availability tradeoff.** `onUnavailable` defaults to **`fail-closed`**: if\n> AER's introspection endpoint is unreachable (network error, 5xx, malformed\n> body) the token is **denied**, so an AER outage can block your protected\n> resource. This is the secure default for admission control. Set\n> `onUnavailable: 'fail-open'` to instead accept the already-offline-verified\n> (signature-valid, unexpired, ≤5 min old) token during an introspection outage,\n> trading a small revocation-latency window for availability.\n\n## Scopes and holder binding (optional)\n\nBeyond audience and signature, `verifyAttestation` can enforce least-privilege\nscopes and bind the token to its holder. All of this is optional; pass only what\nyour resource needs.\n\n```ts\nconst claims = await verifyAttestation(token, {\n  audience: 'mcp://payments-prod',\n  requiredScopes: ['payments:write'], // ALL must be present in the token's scp, else insufficient_scope\n  // DPoP proof-of-possession (RFC 9449): token must carry cnf.jkt and the\n  // request must present a matching proof.\n  requireDpop: true,\n  dpopProof: req.headers.get('DPoP'),\n  method: req.method,\n  url: fullRequestUrl,\n  // mTLS client-cert binding (RFC 8705 x5t#S256): token must carry cnf[\"x5t#S256\"]\n  // and the presented client cert must match.\n  requireMtls: true,\n  mtlsThumbprint: thumbprintFromPeerCert(tlsSocket),\n});\n```\n\nScope enforcement is offline (scopes are signed into the token). DPoP and mTLS\nbinding are off by default; when enabled, a token that isn't bound, or a request\nthat fails to prove possession, is denied. `thumbprintFromPeerCert` and\n`thumbprintFromForwardedClientCert` compute the `x5t#S256` value from a TLS socket\nor a forwarded client-cert header respectively.\n\nThe forwarded-cert header must be set by a trusted mTLS-terminating proxy that\nstrips any inbound client copy first. If a client can set that header it can\nspoof the thumbprint and defeat mTLS binding, so never wire\n`thumbprintFromForwardedClientCert` to a header a client controls. When you\nterminate TLS yourself, use `thumbprintFromPeerCert`: it reads the verified peer\ncertificate off the socket, which a client cannot forge.\n\n## Middleware (optional)\n\n```ts\nimport { honoAerAttestation } from '@adastracomputing/aer-resource-node/hono';\napp.use('/protected/*', honoAerAttestation({ audience: 'mcp://payments-prod' }));\n// claims available at c.get('aerAttestation')\n```\n\n```ts\nimport { expressAerAttestation } from '@adastracomputing/aer-resource-node/express';\napp.use('/protected', expressAerAttestation({ audience: 'mcp://payments-prod' }));\n// claims available at req.aerAttestation\n```\n\nBoth read `X-AER-Attestation` (set `allowBearer: true` to also accept\n`Authorization: Bearer`), are **fail-closed (403)** by default, and accept\n`failOpen: true` to log-and-continue.\n\n## What it proves (and doesn't)\n\n> AER Attestation proves a request was made with a fresh token minted for a\n> running AER session and intended audience. It does **not** prove the host is\n> uncompromised, or that the collector observed every action.\n\nToken theft on a compromised host is bounded by the short TTL (~5 min), and\nfurther by holder binding when you enable it: a DPoP- or mTLS-bound token is\nuseless to anyone who lacks the corresponding key or client certificate.\n\n## License\n\nApache-2.0\n","readmeFilename":""}