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

@axiru/x402-policy-middleware

v0.1.1

Published

Policy pre-authorization middleware for x402 (HTTP 402 Payment Required) flows. Wraps an x402 facilitator request with a governance decision check and emits a signed authorization token the signer can verify before broadcasting on-chain.

Downloads

78

Readme

@axiru/x402-policy-middleware

Policy pre-authorization for x402 (HTTP 402 Payment Required) flows. Wraps an x402 facilitator request with a governance decision check and emits a signed authorization token that the signer verifies before it broadcasts on-chain.

Apache-2.0. Transport agnostic. No I/O of its own.

Why

x402 flows skip your fraud, compliance, and approval gates by design. The agent makes an HTTP call, the resource server replies 402 Payment Required, the agent signs an on-chain transfer, the facilitator broadcasts. There is no merchant of record between the agent and on-chain settlement, and nothing in the protocol asks whether your organization wanted that payment to happen.

This package sits between the agent and the signer and re-introduces that question:

┌─────────┐  402 Payment Required  ┌─────────────┐
│  Agent  │ ─────────────────────► │ Facilitator │
└────┬────┘                        └─────────────┘
     │
     │ authorizeX402Request(challenge, context, deps)
     │
     ▼
┌──────────────────────────┐
│ @axiru/x402-policy-      │── callDecisionEngine ──► your policy decision endpoint
│   middleware             │
│                          │── signAuthorizationToken ──► your signer
└──────────────────────────┘
     │
     │ MiddlewareResult { status: "allowed" | "blocked" | "internal_error" }
     ▼
   Signer verifies the authorization token, then broadcasts
   (or fail-closed refuses to broadcast).

The middleware is transport agnostic, I/O free, and pure beyond its injected dependencies. It runs on Node, Bun, Deno, Cloudflare Workers, or in a Lambda.

Install

npm install @axiru/x402-policy-middleware

The only runtime dependency is @axiru/spec, the shared policy and evidence vocabulary.

Quickstart

import {
  authorizeX402Request,
  toHttpResponse,
  type X402PaymentRequirements,
  type X402RequestContext,
  type MiddlewareDependencies,
} from "@axiru/x402-policy-middleware";

const deps: MiddlewareDependencies = {
  callDecisionEngine: async (ovt, policyInputs) =>
    fetch("https://policy.example.com/v1/decisions", {
      method: "POST",
      body: JSON.stringify({ ovt, policyInputs }),
    }).then((r) => r.json()),

  signAuthorizationToken: async (claims) =>
    fetch("https://policy.example.com/v1/authorizations", {
      method: "POST",
      body: JSON.stringify(claims),
    }).then((r) => r.text()),

  fingerprintOVT: (ovt) => sha256(canonicalJson(ovt)),

  issuer: "https://policy.example.com",
};

// Inside your agent's x402 handler:
const result = await authorizeX402Request(challenge, context, deps);

if (result.status === "allowed") {
  // Retry the facilitator with the authorization token attached:
  await fetch(challenge.resource_url, {
    headers: { "axiru-authorization": result.authorization_token },
  });
} else {
  // Fail-closed: do NOT broadcast.
  const http = toHttpResponse(result);
  return res.status(http.status).json(http.body);
}

fingerprintOVT must be a stable canonical-JSON SHA-256 over the transfer. Any implementation works as long as it is deterministic across processes; the fingerprint is the replay key that ties a decision to the exact transfer it authorized.

Fail-closed contract

The middleware never returns allowed unless both of the following hold:

  1. The decision endpoint explicitly returned allow, and
  2. The signer returned a non-empty token string.

Every other outcome produces a non-allowed result: the decision call throws, the signer throws, the signer returns empty, the payload is structurally invalid, or the decision is deny, quarantine, or require_approval. The signer is contractually required to refuse to broadcast on any non-allowed result.

HTTP status mapping

toHttpResponse maps results to HTTP wire codes:

| Result | Status | Notes | | ------------------------------ | -----: | -------------------------------------------------- | | allowed | 200 | axiru-authorization header carries the JWS token | | blocked (deny) | 403 | Governance refused | | blocked (quarantine) | 423 | Locked, released by a human | | blocked (require_approval) | 428 | Precondition Required, approval queue | | internal_error (anything) | 503 | Fail-closed; signer must refuse |

Authorization-token claims

interface AuthorizationTokenClaims {
  jti: string;                // recorded against the decision record
  iss: string;                // your issuer URL
  sub: string;                // org_id
  aud: string;                // facilitator_url
  iat: number;                // Unix seconds
  exp: number;                // Unix seconds (default iat+120)
  event_id: string;           // decision event id
  ovt_fingerprint: string;    // audit replay key
  rail: "x402";
  rail_action: "pay";
  pay_to_address: string;
  amount_minor_units: string; // serialized bigint
  asset: string;
  chain: string;
  reason_code: string;
}

The host signer JWS-signs these claims. The middleware itself never touches key material.

MPP charge intents

The package also maps Merchant Payment Protocol charge intents onto the same transfer shape, so one policy set covers both x402 and MPP without a second rule language. See mpp-charge-intent.ts and its tests for the mapping.

Related packages

License

Apache-2.0. Copyright 2026 Axiru. See LICENSE.