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

fipsign-sdk

v0.5.2

Published

Post-quantum signing SDK — ML-DSA-65 (NIST FIPS 204)

Readme

fipsign-sdk

Post-quantum signing SDK for Node.js and the browser.

Signs and verifies any payload using ML-DSA-65 (NIST FIPS 204) — the post-quantum digital signature standard resistant to Shor's algorithm. Standardized by NIST in August 2024.

Not just for auth. Sign users, orders, documents, devices, events — any entity that needs a tamper-proof, quantum-resistant signature.


Install

npm install fipsign-sdk

Quick start

1. Create a free account at app.fipsign.dev — enter your email, verify the OTP code sent to your inbox.

2. In the dashboard, create a project, then create an API key inside that project. Save the key — it will not be shown again.

3. Use the key in your app:

import { PQAuth } from 'fipsign-sdk'

const fipsign = new PQAuth('pqa_your_api_key')

sign() — Sign anything

The only required field is sub — any string identifying the entity you want to sign. All other fields are stored in the payload and returned on verify. Cost: 1 token.

// Sign a user session
const { token, meta, usage } = await fipsign.sign({
  sub:              'user_123',
  email:            '[email protected]',
  role:             'admin',
  expiresInSeconds: 3600,           // optional, default 1 hour
})

// Sign an order
const { token } = await fipsign.sign({
  sub:      'order_456',
  amount:   299.99,
  currency: 'USD',
})

// Sign a document
const { token } = await fipsign.sign({
  sub:      'doc_789',
  hash:     'sha256:abc...',
  signedBy: 'alice',
})

// Sign a device
const { token } = await fipsign.sign({
  sub:      'device_iot_001',
  firmware: '2.1.4',
})

// Monitor quota and token source
console.log(`${usage.freeRemaining} free tokens remaining this month`)
console.log(`${usage.packRemaining} pack tokens remaining`)
console.log(`${usage.totalRemaining} total remaining`)
console.log(`charged from: ${meta.source}`) // "free" | "pack" | "free+pack"

sign() response shape

{
  token: {
    payload:   string,  // base64 encoded payload
    signature: string,  // ML-DSA-65 signature
    algorithm: string,  // "ML-DSA-65"
    issuedAt:  number,  // Unix timestamp
  },
  meta: {
    algorithm:        string,  // "ML-DSA-65"
    standard:         string,  // "NIST FIPS 204"
    quantumResistant: boolean,
    expiresIn:        number,  // seconds, as passed to sign()
    issuedFor:        string,  // your developer account email
    projectId:        string,
    tokenCost:        number,  // always 1
    source:           string,  // "free" | "pack" | "free+pack"
  },
  usage: {
    freeRemaining:  number,
    packRemaining:  number,
    totalRemaining: number,
    month:          string,  // e.g. "2026-05"
  }
}

verify() — Verify a token

Never throws. Returns { valid, payload } or { valid: false, error }. Cost: 1 token.

const { valid, payload } = await fipsign.verify(token)

if (!valid) {
  return res.status(401).json({ error: 'Unauthorized' })
}

console.log(payload.sub)   // 'user_123' (or 'order_456', 'doc_789', etc.)
console.log(payload.exp)   // expiry timestamp (Unix)
console.log(payload.iat)   // issued at timestamp (Unix)
// All custom fields passed to sign() are available on payload too

verify() local — Offline, ~1ms

Enable localVerify to verify tokens entirely in memory — no API call, no network latency, no token cost.

const fipsign = new PQAuth({
  apiKey:      'pqa_your_api_key',
  localVerify: true,
})

// Optional: preload public key at startup to avoid first-request latency
await fipsign.preloadPublicKey()

const { valid, payload, local } = await fipsign.verify(token)
console.log(local) // true — verified without an API call

Important: local verification does not check the revocation list. A revoked token will pass local verification if its signature is valid and it has not expired. Use remote verification for sensitive operations (payments, admin actions, etc.).

When server keys are rotated, the SDK automatically detects the mismatch, refreshes the cached key, and retries — no action needed on your end.


revoke() — Revoke a token

Immediately and permanently invalidates a token. Future verify() calls will reject it even if the signature is valid and it hasn't expired. Cost: 1 token.

await fipsign.revoke(token, 'user logged out')
await fipsign.revoke(token, 'order cancelled')
await fipsign.revoke(token, 'suspicious activity detected')

Revoking an already-revoked token returns success without consuming an extra token — the operation is idempotent.

Note: Calling revoke() on an already-expired token returns a 400 error. Expired tokens cannot be submitted for revocation.


middleware() — Express / Fastify

Reads Authorization: Bearer <token> and attaches the decoded payload to req.user. Returns 401 automatically on invalid tokens. Node.js only.

import express from 'express'
import { PQAuth } from 'fipsign-sdk'

const app     = express()
const fipsign = new PQAuth('pqa_your_api_key')

app.use(express.json())

// Login — sign a token and return it base64-encoded to the client
app.post('/login', async (req, res) => {
  const user = await db.users.findByEmail(req.body.email)
  if (!user || !checkPassword(req.body.password, user.passwordHash)) {
    return res.status(401).json({ error: 'Invalid credentials' })
  }

  const { token } = await fipsign.sign({
    sub:              user.id,
    email:            user.email,
    role:             user.role,
    expiresInSeconds: 3600,
  })

  // Encode to base64 — this is what the client puts in Authorization: Bearer <encoded>
  const encoded = Buffer.from(JSON.stringify(token)).toString('base64')
  res.json({ token: encoded })
})

// Logout — decode the header and revoke the token immediately
app.post('/logout', async (req, res) => {
  const header = req.headers['authorization'] ?? ''
  if (header.startsWith('Bearer ')) {
    try {
      const token = JSON.parse(Buffer.from(header.slice(7), 'base64').toString('utf8'))
      await fipsign.revoke(token, 'user logged out')
    } catch { /* ignore malformed token */ }
  }
  res.json({ success: true })
})

// Protect all routes under /api with the FIPSign middleware
app.use('/api', fipsign.middleware())

// req.user is the verified payload — sub, email, role, exp, iat, etc.
app.get('/api/profile', (req, res) => {
  res.json({ user: req.user })
})

app.listen(3000)

usage() — Token balance

Free tokens reset on the 1st of each month (UTC). Pack tokens never expire and accumulate across purchases. No token cost.

const { current, monthlyHistory, packs, developer } = await fipsign.usage()

// Current balance
console.log(`Month: ${current.month}`)                          // e.g. "2026-05"
console.log(`Free:  ${current.freeRemaining} / ${current.freeLimit}`)
console.log(`Used:  ${current.freeUsed} this month`)
console.log(`Pack:  ${current.packRemaining}`)
console.log(`Total: ${current.totalRemaining}`)
console.log(`Account: ${developer.email}`)

// 6-month history (always 6 entries, months with no activity show 0)
monthlyHistory.forEach(({ month, tokensUsed, fromFree, fromPack }) => {
  console.log(`${month}: ${tokensUsed} used (${fromFree} free + ${fromPack} pack)`)
})

// Purchased packs
packs.forEach(({ packType, tokensPurchased, purchasedAt }) => {
  console.log(`${packType}: ${tokensPurchased} tokens — ${new Date(purchasedAt * 1000).toLocaleDateString()}`)
})

webhooks — Real-time notifications

Events: token.signed · token.rejected · token.revoked · limit.warning · limit.reached

// Register
const { webhook } = await fipsign.webhooks.register({
  url:    'https://yourapp.com/webhooks/fipsign',
  events: ['limit.warning', 'limit.reached', 'token.revoked'],
})

// Store webhook.secret securely — it won't be shown again
console.log(webhook.secret)

// Send a test event to confirm your endpoint is reachable
await fipsign.webhooks.test()

// Get current config (secret is never returned after registration)
const { webhook: config } = await fipsign.webhooks.get()
// config is null if no webhook has been registered yet
if (!config) console.log('No webhook configured')

// Delete
await fipsign.webhooks.delete()

Re-registering an existing webhook updates the URL and events but preserves the original secret. To rotate the secret, delete and re-register.

Verifying incoming webhook requests

Each incoming POST includes the headers X-PQAuth-Event, X-PQAuth-Signature (sha256=...), and X-PQAuth-Timestamp.

import crypto from 'crypto'

app.post('/webhooks/fipsign', express.json(), (req, res) => {
  const sig      = req.headers['x-pqauth-signature'] as string
  const expected = 'sha256=' + crypto
    .createHmac('sha256', process.env.FIPSIGN_WEBHOOK_SECRET!)
    .update(JSON.stringify(req.body))
    .digest('hex')

  if (!crypto.timingSafeEqual(Buffer.from(sig), Buffer.from(expected))) {
    return res.status(401).send('Invalid signature')
  }

  const { event, data } = req.body

  switch (event) {
    case 'limit.warning':
      console.warn(`Usage warning — ${data.freeRemaining} free tokens left this month`)
      break
    case 'limit.reached':
      console.error(`Limit reached — pack remaining: ${data.packRemaining}`)
      break
    case 'token.revoked':
      console.log(`Token revoked for sub: ${data.sub}`)
      break
  }

  res.status(200).send('ok')
})

Error handling

verify() never throws — it always returns { valid, payload } or { valid: false, error }. All other methods throw PQAuthError on failure.

import { PQAuth, PQAuthError } from 'fipsign-sdk'

try {
  await fipsign.sign({ sub: 'user_123' })
} catch (err) {
  if (err instanceof PQAuthError) {
    switch (err.code) {
      case 'INVALID_API_KEY':       // key missing or doesn't start with pqa_
        break
      case 'API_ERROR':             // server returned an error (check err.status)
        break
      case 'TIMEOUT':               // request exceeded timeout (default: 10s)
        break
      case 'NETWORK_ERROR':         // connection failed
        break
      case 'MISSING_SUB':           // sign() called without sub
        break
      case 'INVALID_SIGNATURE':     // local verify: token tampered
        break
      case 'TOKEN_EXPIRED':         // local verify: token expired
        break
      case 'UNSUPPORTED_ALGORITHM': // local verify: unknown algorithm
        break
    }
    console.error(err.code, err.message, err.status)
  }
}

Token quota

Every account gets 10,000 free tokens per month, reset on the 1st (UTC). Unused free tokens do not carry over. Additional tokens are available as non-expiring packs, purchased from the dashboard.

Each of these operations costs 1 token: signing (/sign), verification (/verify), and revocation (/revoke). Checking usage (/usage) and fetching the public key (/public-key) are free.


Rate limits

300 requests per minute per API key on /sign, /verify, and /revoke. On excess the API returns HTTP 429.

Token quota and rate limits are separate controls — check the error message to distinguish them:

  • "Rate limit exceeded" → back off and retry with exponential backoff
  • "Token limit reached" → purchase a pack from the dashboard, retrying won't help

Constructor options

const fipsign = new PQAuth({
  apiKey:      'pqa_...',                    // required — must start with pqa_
  baseUrl:     'https://api.fipsign.dev',    // optional, override for self-hosting
  timeout:     10_000,                       // optional, ms (default: 10000)
  localVerify: false,                        // optional, in-memory verification (default: false)
})

| Option | Type | Default | Description | |---|---|---|---| | apiKey | string | — | Required. From the dashboard. Constructor throws immediately if not prefixed with pqa_. | | baseUrl | string | https://api.fipsign.dev | Override for local dev or self-hosted instances. | | timeout | number | 10000 | Request timeout in ms. Throws TIMEOUT on exceeded. | | localVerify | boolean | false | When true, verify() runs in memory using a cached public key (refreshed every hour). No API call, no token cost. Does not check revocation. |


Why ML-DSA-65?

JWT with RS256/ES256 and standard OAuth tokens use ECDSA or RSA — both vulnerable to Shor's algorithm running on a sufficiently powerful quantum computer. ML-DSA-65 is based on the hardness of lattice problems (Module-LWE / Module-SIS), which have no known quantum speedup. It was standardized by NIST in August 2024 as FIPS 204.


Links