npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@adastracomputing/aer-resource-node

v0.1.1

Published

Verify AER Attestation tokens at a protected resource or MCP server, offline against cached JWKS, fail-closed.

Readme

@adastracomputing/aer-resource-node

Verify AER Attestation tokens at a protected resource or MCP server. A registered agent (running the AER auto-collector) presents a short-lived token; this library verifies it offline against cached JWKS, fail-closed, so requests without a valid token are denied.

Zero runtime dependencies. The Hono/Express middleware are optional subpath exports.

Install

npm install @adastracomputing/aer-resource-node

Requires Node 20 or newer.

Verify a token

import { verifyAttestation, AttestationError } from '@adastracomputing/aer-resource-node';

try {
  const claims = await verifyAttestation(token, { audience: 'mcp://payments-prod' });
  // claims.agent_id / agent_session_id / tenant_id / environment_id …
} catch (e) {
  if (e instanceof AttestationError) { /* deny: e.code */ }
}

Defaults: issuer and jwksUrl point at aer-api.adastra.computer; 30s clock tolerance. JWKS is cached (honoring max-age) and refetched on an unknown kid.

Revocation check (optional introspection)

Offline verify (signature plus short TTL) is the default and needs no network call past JWKS. To also honor revocation within the token's lifetime, pass introspect: after the offline check the verifier asks AER whether the token is still active (jti not revoked, session still running).

const claims = await verifyAttestation(token, {
  audience: 'mcp://payments-prod',
  introspect: {
    url: 'https://api.aer.run/v1/attestations/introspect',
    verifierKey: process.env.AER_VERIFIER_KEY!, // aerv_… ; mint via admin
    // activeCacheSec: 10,  // cache an active verdict (default 10s, hard max 30s, never past exp)
    // onUnavailable: 'fail-closed',
  },
});

Positive verdicts are cached briefly, so revocation takes effect within activeCacheSec (default 10s). An inactive verdict throws AttestationError('revoked', reason).

Availability tradeoff. onUnavailable defaults to fail-closed: if AER's introspection endpoint is unreachable (network error, 5xx, malformed body) the token is denied, so an AER outage can block your protected resource. This is the secure default for admission control. Set onUnavailable: 'fail-open' to instead accept the already-offline-verified (signature-valid, unexpired, ≤5 min old) token during an introspection outage, trading a small revocation-latency window for availability.

Scopes and holder binding (optional)

Beyond audience and signature, verifyAttestation can enforce least-privilege scopes and bind the token to its holder. All of this is optional; pass only what your resource needs.

const claims = await verifyAttestation(token, {
  audience: 'mcp://payments-prod',
  requiredScopes: ['payments:write'], // ALL must be present in the token's scp, else insufficient_scope
  // DPoP proof-of-possession (RFC 9449): token must carry cnf.jkt and the
  // request must present a matching proof.
  requireDpop: true,
  dpopProof: req.headers.get('DPoP'),
  method: req.method,
  url: fullRequestUrl,
  // mTLS client-cert binding (RFC 8705 x5t#S256): token must carry cnf["x5t#S256"]
  // and the presented client cert must match.
  requireMtls: true,
  mtlsThumbprint: thumbprintFromPeerCert(tlsSocket),
});

Scope enforcement is offline (scopes are signed into the token). DPoP and mTLS binding are off by default; when enabled, a token that isn't bound, or a request that fails to prove possession, is denied. thumbprintFromPeerCert and thumbprintFromForwardedClientCert compute the x5t#S256 value from a TLS socket or a forwarded client-cert header respectively.

The forwarded-cert header must be set by a trusted mTLS-terminating proxy that strips any inbound client copy first. If a client can set that header it can spoof the thumbprint and defeat mTLS binding, so never wire thumbprintFromForwardedClientCert to a header a client controls. When you terminate TLS yourself, use thumbprintFromPeerCert: it reads the verified peer certificate off the socket, which a client cannot forge.

Middleware (optional)

import { honoAerAttestation } from '@adastracomputing/aer-resource-node/hono';
app.use('/protected/*', honoAerAttestation({ audience: 'mcp://payments-prod' }));
// claims available at c.get('aerAttestation')
import { expressAerAttestation } from '@adastracomputing/aer-resource-node/express';
app.use('/protected', expressAerAttestation({ audience: 'mcp://payments-prod' }));
// claims available at req.aerAttestation

Both read X-AER-Attestation (set allowBearer: true to also accept Authorization: Bearer), are fail-closed (403) by default, and accept failOpen: true to log-and-continue.

What it proves (and doesn't)

AER Attestation proves a request was made with a fresh token minted for a running AER session and intended audience. It does not prove the host is uncompromised, or that the collector observed every action.

Token theft on a compromised host is bounded by the short TTL (~5 min), and further by holder binding when you enable it: a DPoP- or mTLS-bound token is useless to anyone who lacks the corresponding key or client certificate.

License

Apache-2.0