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

@mandate-security/node

v0.3.0

Published

MANDATE verification for Node.js: hosted cross-referenced validation by default, plus the offline DEADMAN emergency tier and legacy local verification.

Readme

@mandate-security/node

Verification of MANDATE decisions for Node.js. Add one script tag on the frontend and keep production browser authority server-side with the HttpOnly Mndt-Sess continuity cookie or locked hosted validation. Hosted cross-referenced validation is the default authority for protected routes; local X-Mndt verification is the offline/emergency and compatibility path — ordinary low-risk routes, explicit server integrations, incident response when MANDATE is unreachable, and migrations. Local verification keeps no replay state and cannot consult replay markers, lineage, or session trust; high-value or replay-sensitive routes must call hosted validation with a tokens:validate API key.

npm scope: @mandate-security — the @mandate scope is registered by an unrelated project on npm.

Requires Node.js 18+.

Quick start

1. Frontend (browser)

Add the MANDATE script before calling routes your backend protects. Public builds keep tokens private to the verifier runtime and attach X-Mndt automatically on same-origin protected requests.

<script src="https://gate.x-lock.dev/g.js?k=YOUR_SITE_KEY" async></script>
const res = await fetch("/api/checkout", {
  method: "POST",
  headers: { "Content-Type": "application/json" },
  body: JSON.stringify({ cartId: "..." }),
});

2. Backend (Node)

npm install @mandate-security/node

Set env vars (shown once in the MANDATE dashboard):

MANDATE_SITE_SECRET=mss_live_...              # server-only current secret
MANDATE_SITE_KEY=sk_live_...                  # optional but recommended
MANDATE_MIN_SCORE=0.75                        # optional
MANDATE_PREVIOUS_SITE_SECRET=mss_live_old_... # rotation overlap only (optional)

Current / previous keys: set MANDATE_SITE_SECRET (or siteSecret) to the current secret only. During an explicit dashboard rotation overlap, also set MANDATE_PREVIOUS_SITE_SECRET (or previousSiteSecret) so tokens/cookies sealed with the previous secret still verify. After you retire the previous version in the dashboard, remove the previous env var and redeploy — unknown/retired keys fail closed as invalid_token / signature. Optional currentKeyId / previousKeyId pin expected token kid values during overlap.

Verify a token:

import { verifyRequest } from "@mandate-security/node";

const result = verifyRequest(req.headers, {
  siteSecret: process.env.MANDATE_SITE_SECRET,
  siteKey: process.env.MANDATE_SITE_KEY,
  minScore: 0.75,
});

if (!result.success) {
  return res.status(403).json({ error: result.error });
}

Or bind env vars once:

import { createVerifier } from "@mandate-security/node";

const mandate = createVerifier(); // reads MANDATE_* env vars

export function requireMandate(req) {
  const result = mandate.verifyRequest(req.headers);
  if (!result.success || result.action !== "allow") throw new Error(result.error ?? "forbidden");
  return result;
}

Production browser authority (Mndt-Sess)

In production, browsers carry an HttpOnly Mndt-Sess continuity cookie (max 5 minutes, path-bound). Verify it on first-party protected routes:

import { verifySessionCookieRequest } from "@mandate-security/node";

const result = verifySessionCookieRequest(req, {
  siteSecret: process.env.MANDATE_SITE_SECRET,
  // path is inferred from req.path / req.url when omitted
  // previousSiteSecret also reads MANDATE_PREVIOUS_SITE_SECRET during rotation overlap
  // allowLegacy: true, // only during an explicit v1 reader overlap; default false
});

// Prefer success + action checks — `human` is a legacy alias, not identity proof.
if (!result.success || result.action !== "allow") {
  return res.status(403).json({ error: result.error });
}

Local X-Mndt verification remains appropriate for ordinary low-risk routes, explicit server integrations, and migrations. Do not log raw cookie values, ciphertext, site secrets, or decrypted claims. Prefer summarizeDecision(result) for logs/metrics.

Ordinary local verification contract (no hosted dependency)

Ordinary routes verify entirely in-process with your site secret:

| Property | Behavior | | --- | --- | | Network | None — never calls MANDATE infrastructure | | Timeout | N/A — synchronous CPU crypto; no I/O wait or deadline config | | Failure | Structured { success: false, error } (fail-closed); adapters do not throw on bad credentials | | High-value | Local highValue: true fails closed with high_value_requires_hosted_validation |

Measured p95 on Node 22 (darwin/arm64, 5000 iters): see docs/internal/evidence/m1-03-local-verify-benchmark.json. Soft target ≈ 5 ms; re-run with:

npm run benchmark:local-verify --prefix sdks/node

Observe / enforce adapter semantics

| mode | sessionCookie | Missing/invalid credential | | --- | --- | --- | | observe | off (header X-Mndt) | Continues; req.mandate / context.mandate set | | observe | observe or enforce | Continues (cookie path) | | enforce | off | 403 (header path) | | enforce | observe | Continues — measure cookie outcomes without blocking | | enforce | enforce | 403 only when both are enforce |

Rollback: set mode: "observe" (and sessionCookie: "observe" if using cookies), redeploy, keep existing app auth. Do not flip broad enforce without an approved single-route plan.

Use hosted validation when a route needs stateful replay protection or local verification cannot run in your backend. Hosted validation is the default authority for protected routes; local verification remains for ordinary low-risk routes, offline incident response, and compatibility migrations, and setting highValue: true on local verification fails closed with high_value_requires_hosted_validation. Hosted validation consumes each raw X-Mndt token once and asks the gate to check live session, origin, route-seed, server-counter, delta-cadence, token-context, and browser request-proof continuity. High-value hosted validation requires a customer API key with the tokens:validate scope before the SDK makes the call:

import { validateHostedRequest } from "@mandate-security/node";

const result = await validateHostedRequest(req, {
  siteSecret: process.env.MANDATE_SITE_SECRET,
  siteKey: process.env.MANDATE_SITE_KEY,
  apiKey: process.env.MANDATE_API_KEY,
  gateUrl: process.env.MANDATE_GATE_URL, // optional; defaults to https://gate.x-lock.dev
  highValue: true,
  path: req.path,
  origin: "https://app.example.com",
  accountKey: req.user?.id,
});

if (!result.success) {
  return res.status(403).json({ error: result.error });
}
// If result.token is set, it is a refreshed opaque token with updated
// server-side lineage/marker/route state for follow-on checks.
// Under abuse pressure, result.action can be "throttle", "fresh_proof", "queue", or "step_up".
// If result.queueToken is set, pass it back as queueToken on the server-side retry.

Offline emergency verification (DEADMAN)

DEADMAN is the tourniquet tier: a short-lived, route-scoped proof your backend verifies entirely in-process with your site secret — zero API callback to MANDATE, so enforcement keeps working even if our edge is unreachable. Use it for night-one incident mitigation on attacked routes (login, order, redemption), then graduate to hosted cross-referenced verification, which remains the default authority for protected routes.

DEADMAN is stateless by design: it cannot consult replay markers, token lineage, or session trust, and there is no revocation. Replay is possible inside the token TTL (minutes, not hours). That residual risk is the tradeoff for a verifier that never phones home — a tourniquet, not the cure.

import { deadmanMiddleware } from "@mandate-security/node";

app.post(
  "/api/login",
  deadmanMiddleware({
    siteSecret: process.env.MANDATE_SITE_SECRET,
    routeClass: "login", // proofs minted for other route classes are denied
  }),
  loginHandler, // req.mandateDeadman carries the verified payload
);

The middleware requires a valid proof on the md_kx header (case-insensitive; the x-mndt-deadman alias is accepted during transition). Missing or invalid proof is fail-closed: a uniform 403 {"error":"deadman_required"} that never reveals which check failed.

For direct verification, verifyDeadmanToken(token, { siteSecret, siteKey, routeClass }) returns { ok: true, payload } or { ok: false, reason } with stable reasons (malformed, bad_signature, decrypt_failed, wrong_type, expired, site_mismatch, route_mismatch). It never throws on bad input and never calls MANDATE infrastructure.

Express

import express from "express";
import { summarizeDecision } from "@mandate-security/node";
import { mandate } from "@mandate-security/node/express";

const app = express();
const mandateMode = process.env.MANDATE_MODE ?? "observe";

// Ordinary / migration: header X-Mndt
app.use(mandate({
  siteSecret: process.env.MANDATE_SITE_SECRET,
  siteKey: process.env.MANDATE_SITE_KEY,
  mode: mandateMode, // observe first; enforcement needs approved route scope and rollback
  minScore: 0.75,
  onDecision: (d, req) => {
    // Log only grouped fields — never raw tokens, cookies, or secrets.
    console.log({ path: req.path, ...summarizeDecision(d) });
  },
}));

// Production browser authority: HttpOnly Mndt-Sess (path-bound)
app.post(
  "/api/checkout",
  mandate({
    siteSecret: process.env.MANDATE_SITE_SECRET,
    mode: mandateMode,
    sessionCookie: mandateMode === "enforce" ? "enforce" : "observe",
  }),
  (req, res) => {
    if (mandateMode === "enforce" && (!req.mandate.success || req.mandate.action !== "allow")) {
      return res.status(403).json({ error: req.mandate.error });
    }
    return res.json({ ok: true, mandate: { action: req.mandate.action } });
  },
);

Observe first: start in mode: "observe" (and sessionCookie: "observe" when using cookies) so every request proceeds and req.mandate is always set. Keep existing controls, review legitimate-user outcomes, and test rollback. Enforcement is an opt-in decision for one approved route, not a broad browser-blocking claim. Prefer success && action === "allow" over the legacy human alias.

For high-value routes that need hosted replay/session continuity and abuse escalation handling, use mandateHosted on the specific route:

import { mandateHosted } from "@mandate-security/node/express";

app.post(
  "/api/login",
  mandateHosted({
    siteSecret: process.env.MANDATE_SITE_SECRET,
    siteKey: process.env.MANDATE_SITE_KEY,
    apiKey: process.env.MANDATE_API_KEY,
    highValue: true,
    origin: "https://app.example.com",
    resolveHostedOptions: (req) => ({
      accountKey: req.user?.id,
      queueToken: req.get("X-Mandate-Queue-Token"),
      clientIP: req.get("CF-Connecting-IP"),
      asn: req.get("CF-ASN"),
      country: req.get("CF-IPCountry"),
    }),
  }),
  loginHandler,
);

In enforce mode, hosted middleware maps throttle to 429, queue to 202 with queueToken, fresh_proof to 401, step_up to 403 with stepUp/stepUpAttemptId, and block to 403.

Next.js (App Router)

// app/api/checkout/route.js
import { withMandate } from "@mandate-security/node/next";

export const POST = withMandate(
  async (_request, { mandate }) => {
    if (process.env.MANDATE_MODE === "enforce" && (!mandate.success || mandate.action !== "allow")) {
      return Response.json({ error: mandate.error }, { status: 403 });
    }
    return Response.json({ ok: true, mandate: { action: mandate.action } });
  },
  {
    siteSecret: process.env.MANDATE_SITE_SECRET,
    siteKey: process.env.MANDATE_SITE_KEY,
    mode: process.env.MANDATE_MODE ?? "observe",
    // Production browser authority (HttpOnly Mndt-Sess). Omit for ordinary X-Mndt routes.
    // sessionCookie: process.env.MANDATE_MODE === "enforce" ? "enforce" : "observe",
  },
);

In mode: "enforce", failed verification returns 403 before your handler runs. With sessionCookie: "enforce", the middleware verifies Mndt-Sess instead of X-Mndt.

For hosted validation on a sensitive App Router route:

// app/api/login/route.js
import { withMandateHosted } from "@mandate-security/node/next";

export const POST = withMandateHosted(
  async (_request, { mandate }) => {
    return Response.json({ ok: true, sessionId: mandate.sessionId });
  },
  {
    siteSecret: process.env.MANDATE_SITE_SECRET,
    siteKey: process.env.MANDATE_SITE_KEY,
    apiKey: process.env.MANDATE_API_KEY,
    highValue: true,
    origin: "https://app.example.com",
    resolveHostedOptions: (request) => ({
      accountKey: request.headers.get("X-Account-Key") ?? undefined,
      queueToken: request.headers.get("X-Mandate-Queue-Token") ?? undefined,
      clientIP: request.headers.get("CF-Connecting-IP") ?? undefined,
      asn: request.headers.get("CF-ASN") ?? undefined,
      country: request.headers.get("CF-IPCountry") ?? undefined,
    }),
  },
);

API reference

verify(token, options) / verifyMandateToken(token, options)

Verify a raw token string with compatible local header-token verification; it adds no MANDATE validation round trip. For sensitive local routes, pass path, endpoint, or route; high-route tokens then must carry a matching route proof or verification returns route_proof_missing / route_proof_mismatch.

verifyRequest(headers, options)

Read X-Mndt from Fetch Headers, Express req, or a plain header map, then verify. Pass endpoint metadata in options when the route should enforce a local high-route proof.

verifySessionCookie(value, options) / verifySessionCookieRequest(source, options)

Verify production browser authority from the HttpOnly Mndt-Sess cookie (v2 encrypted envelope with gate parity). Options: siteSecret, optional previousSiteSecret / MANDATE_PREVIOUS_SITE_SECRET (rotation overlap only), path (binding; empty → /, max 256), now, allowLegacy (default false; not env-enabled), and optional expected token-payload bindings (sessionId, siteKey, routeSeed, origin, tokenId, generation).

Stable errors: missing, malformed, version, signature, lifetime, expired, issued_in_future, path_mismatch, site_mismatch, session_mismatch, route_seed_mismatch, origin_mismatch, token_mismatch, generation_mismatch, unavailable. Never log raw cookies, ciphertext, or secrets. Use summarizeDecision for customer-safe logs.

summarizeDecision(result)

Returns grouped fields only (success, action, score, sessionId, siteKey, keyId, routeClass, error) for metrics/logs. Never includes raw tokens, cookies, or secrets.

createVerifier(options?)

Returns { verify, verifyRequest, verifySessionCookie, verifySessionCookieRequest, validateHosted, validateHostedRequest, readToken, readSessionCookie, header }. Reads MANDATE_SITE_SECRET, MANDATE_SITE_KEY, MANDATE_MIN_SCORE, optional MANDATE_PREVIOUS_SITE_SECRET, optional MANDATE_GATE_URL, and optional MANDATE_API_KEY when options are omitted. Bound verify methods are fail-closed (never throw on bad credentials).

validateHosted(token, options) / validateHostedRequest(headers, options)

Calls locked hosted POST /validate for high-value or replay-sensitive paths that need one-shot token consumption plus server-side replay, session-continuity, origin, route-seed, server-counter, delta-cadence, token-context, and browser request-proof checks. Pass the full request object when available so validateHostedRequest can forward X-Mndt-Req, method, and path. Options include gateUrl, validateUrl, apiKey, siteSecret, siteKey, minScore, highValue, endpointValue, path, endpoint, route, requestProof, requestMethod, origin, siteOrigin, accountKey, queueToken, and hosted middleware resolveHostedOptions. When available from trusted edge/backend metadata, also pass clientIP, ipAddress, asn, and country so MANDATE can score token replay across network changes without making local verification phone home. Hosted validation does not expose raw scores. Reusing the same hosted-validated token returns token_replayed; high-value stale lineage can return stale_token, delta_cadence_stale, route_proof_missing / route_proof_mismatch, or request_proof_missing / request_proof_mismatch. It may return token, a refreshed opaque token with updated server-side lineage/marker state. Result shapes expose tokenMarker as a compact diagnostic marker: p means provisional and e means escalated. Customers should not branch security policy on marker values directly. Hosted validation may report routeClass as low, mid, or high; when the gate returns a route-scoped refresh, tokenTtlSeconds describes the refreshed token lifetime (900, 300, or 60). For throttled abuse-escalation decisions, hosted validation may include cache/stale-content hints: cacheAction, cacheTtlSeconds, and staleIfErrorSeconds.

Result shape

{
  success: boolean;
  action: "allow" | "observe" | "throttle" | "fresh_proof" | "queue" | "step_up" | "challenge" | "block" | null;
  score: number | null;        // local verification only; hosted validation returns null
  human: boolean;              // legacy alias for success && action === "allow"; not identity proof
  siteKey: string | null;
  sessionId: string | null;
  expiresAt: number | null;    // unix seconds
  token?: string | null;        // hosted validation only
  routeClass: string | null;    // low | mid | high when route-scoped
  tokenTtlSeconds: number | null;
  tokenMarker: "p" | "e" | string | null; // compact marker, diagnostic only
  reason: string | null;
  reasons: string[];
  retryAfterSeconds: number | null;
  queueToken: string | null;
  recommendedStepUp: string | null;
  stepUpAttemptId: string | null;
  cacheAction: string | null;
  cacheTtlSeconds: number | null;
  staleIfErrorSeconds: number | null;
  error?: "missing_token" | "invalid_token" | "expired_token"
        | "token_replayed" | "stale_token" | "delta_cadence_stale"
        | "route_proof_missing" | "route_proof_mismatch"
        | "request_proof_missing" | "request_proof_invalid"
        | "request_proof_stale" | "request_proof_mismatch"
        | "request_proof_unavailable"
        | "wrong_site_key" | "below_min_score" | "blocked" | "challenge";
}

Notes

  • Production browser authority uses the HttpOnly Mndt-Sess cookie (max 5 minutes, path-bound, encrypted v2). Ordinary local routes use X-Mndt header tokens (default 15-minute TTL). Hosted /validate is the default authority for protected routes and is required for high-value/replay-sensitive one-shot consumption.
  • Tokens and session cookies are opaque encrypted binary (not JWTs). Semantic claims are not customer-loggable credentials.
  • Local verification keeps no replay state. It can enforce endpoint-bound high-route token proofs when you pass path, endpoint, or route; use hosted validation for high-value paths that need MANDATE's live replay/session/token-context/request-proof checks.
  • Never expose your site secret to the client. Never log raw Mndt-Sess / X-Mndt values, decrypted claims, or secrets.

Docs

Full documentation: x-lock.dev/docs

Generate an integration guide for your app:

./mandate init --target ./your-app --framework express

Tests

Shared crypto vectors: test/token-vectors.json.

Shared protocol corpus (M1-02): test/browser-credential-protocol-fixtures.json (X-Mndt + Node cookie cases).

cd sdks/node && npm test
npm run benchmark:local-verify --prefix sdks/node   # M1-03 p95 evidence

License

MIT