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

@tillstack/auth-node

v0.5.0

Published

Node SDK for TillAuth — JWT verification + middleware

Readme

@tillstack/auth-node

Server-side TillAuth SDK for Node.js — verify TillAuth JWTs and protect your routes. Verification is offline against a cached JWKS (EdDSA), so there is no round-trip to TillAuth on the hot path.

Install

npm install @tillstack/auth-node
# or: pnpm add @tillstack/auth-node

Usage

import { createVerifier } from '@tillstack/auth-node'

const verifier = createVerifier({
  appId: 'tau_your_app_id', // the app's public id (its publishable key or app id works too)
  // apiBase: 'https://auth.tilldev.dev', // default
  // issuer: 'https://auth.tilldev.dev/realms/<app id>', // refuse the shared key once the app has its own
  // requireMfa: true,
})

// Verify a raw token, or pull it straight from an Authorization header:
const claims = await verifier.verifyHeader(req.headers.authorization)
// claims.sub, claims.email, claims.mfa, claims.exp

Express

import express from 'express'
import { createVerifier, expressMiddleware } from '@tillstack/auth-node'

const app = express()
const verifier = createVerifier({ appId: 'tau_your_app_id' })

app.use(expressMiddleware(verifier)) // sets req.user to the verified claims

Fastify

import { createVerifier, fastifyHook } from '@tillstack/auth-node'

const verifier = createVerifier({ appId: 'tau_your_app_id' })
fastify.addHook('preHandler', fastifyHook(verifier)) // sets req.user

Webhooks

import express from 'express'
import { verifyWebhook, TillAuthWebhookError } from '@tillstack/auth-node'

const app = express()

// Express: mount with express.raw({ type: 'application/json' }) so req.body is the raw bytes.
app.post('/webhooks/tillauth', express.raw({ type: 'application/json' }), async (req, res) => {
  try {
    const event = await verifyWebhook(req.body, req.get('x-tillauth-signature'), process.env.TILLAUTH_WEBHOOK_SECRET!)
    // event.type, event.user_id, event.delivery_id
    res.sendStatus(204)
  } catch (e) {
    if (e instanceof TillAuthWebhookError) return res.status(400).send(e.reason)
    throw e
  }
})

Rejects a bad signature, a timestamp older than five minutes, and a body that was re-serialized.

Signing keys

The verifier picks the key set from the token's issuer: tokens signed with the app's own key are checked against https://auth.tilldev.dev/realms/<appId>/.well-known/jwks.json, which holds only that app's keys; tokens from an app still on the shared key are checked against https://auth.tilldev.dev/.well-known/jwks.json. Another app's tokens are refused either way. Pin issuer to the app's issuer to refuse the shared key entirely.

For fully air-gapped verification, pass inline public keys via publicJwks instead of letting the SDK fetch them. A rotation publishes the new key 15 minutes before it signs and the previous key verifies for 24 hours after, so update the inline keys when you rotate.

Internal apps

When a TillAuth internal app sits in front of your tool, the proxy forwards the person's identity as X-TillDev-Email, X-TillDev-Role and friends, plus X-TillDev-Assertion, a token signed for that internal app and that host only. Verify the assertion instead of trusting the plain headers, so a request that skipped the proxy can't claim to be someone:

import { createAccessVerifier, AccessAssertionError } from '@tillstack/auth-node'

const access = createAccessVerifier({
  issuer: process.env.TILLDEV_ACCESS_ISSUER!,     // shown on the internal app's page
  audience: process.env.TILLDEV_ACCESS_AUDIENCE!, // its taac_… id
})

app.use(async (req, res, next) => {
  try {
    req.user = await access.verifyRequest(req.headers) // email, role, groups, mfa, auth_time, sub
    next()
  } catch (e) {
    if (e instanceof AccessAssertionError) return res.status(401).send(e.code)
    next(e)
  }
})

verifyRequest takes Node, Express or Fastify headers, or a fetch Headers, and refuses an assertion issued for another host. It lasts 5 minutes and is reused across that person's requests for up to 4 of them, so it always arrives with a minute or more left; it is not a one-time token.

Docs

Full documentation: https://tilldev.dev/docs

License

Apache-2.0