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

@everystack/auth

v0.2.1

Published

JWT authentication handlers, password hashing, and React auth context

Readme

@everystack/auth

JWT auth for Expo apps. Zero runtime dependencies. SQL-compatible. Edge-verifiable.

Why

Most JWT libraries (jose, jsonwebtoken, ...) are large dependencies that:

  1. Don't run in CloudFront Functions (no Buffer, TextEncoder, crypto.subtle)
  2. Aren't byte-compatible with a Postgres-only implementation
  3. Pull in WebCrypto polyfills you don't need on Node

This package provides one HS256 envelope that runs in three places — Node, Postgres, and CloudFront Functions — and produces byte-identical tokens in all three.

Three Deployment Modes

| Mode | Mint tokens | Verify tokens | Use when | |------|-------------|---------------|----------| | JS-only | Lambda (Node) | Lambda + CFF (edge) | Standard Expo + SST app | | SQL-only | Postgres (jwt_sign) | Postgres (jwt_verify) | Pure PostgREST, no Lambda | | Hybrid | Either | Either | DB issues long-lived refresh, edge verifies short-lived access |

All three produce the same wire format: header.payload.signature, base64url, no padding, HS256.

Install

pnpm add @everystack/auth

Zero runtime dependencies. drizzle-orm and react are optional peer deps for the schema and client exports.

Entry Points

| Export | Purpose | |--------|---------| | @everystack/auth | High-level handlers: createAuthHandlers, verifyToken, OAuth providers | | @everystack/auth/jwt | Low-level createJwt({ secret, hmac }) — runtime-agnostic envelope | | @everystack/auth/jwt/node | hmacNode — HMAC backed by node:crypto | | @everystack/auth/jwt/web | hmacWeb — HMAC backed by crypto.subtle | | @everystack/auth/jwt/sql | SQL helpers for the Postgres twin (jwt_sign, jwt_verify) | | @everystack/auth/oauth | verifyOidcToken (RS256+JWKS), Google, Apple | | @everystack/auth/cff | generateCffVerifier() — emits a verifier as a string for CloudFront Functions | | @everystack/auth/client | React AuthProvider, useAuth | | @everystack/auth/api | API client wired with auto-refresh | | @everystack/auth/schema | Drizzle schema for refresh_tokens, oauth_accounts |

The Envelope

Library owns:

  • {"alg":"HS256","typ":"JWT"} header (literal, not negotiated)
  • base64url encoding (RFC 4648 §5, no padding)
  • iat / exp math, configurable TTL and clock skew
  • Optional jti
  • Constant-time signature compare
  • Algorithm pinning (rejects alg=none, alg=HS512, RSA confusion)

App owns:

  • Claim shape (sub / user_id / whatever your DB uses)
  • Role accessor (where to read role from claims)
  • Subject accessor
import { createJwt } from '@everystack/auth/jwt';
import { hmacNode } from '@everystack/auth/jwt/node';

const jwt = createJwt({
  secret: process.env.JWT_SECRET!,
  hmac: hmacNode,
  ttlSec: 3600,
  clockSkewSec: 30,
  includeJti: true,
  // Optional accessors so the verifier knows where to look in your custom claim shape:
  getSubject: (c) => c.user_id ?? c.sub,
  getRole:    (c) => c.role,
  getExpiry:  (c) => c.exp,
});

const token  = await jwt.sign({ user_id: 'u_123', role: 'admin', email: '[email protected]' });
const claims = await jwt.verify(token);  // null if invalid/expired

High-Level Handlers

import { createAuthHandlers, createAppleProvider, createGoogleProvider } from '@everystack/auth';
import { refreshTokens, oauthAccounts } from '@everystack/auth/schema';
import { createDb, getJwtSecret } from '@everystack/server/db';
import * as schema from '../db/schema';

const { db } = createDb(schema);
const auth = createAuthHandlers(
  db,
  { ...schema, refreshTokens, oauthAccounts },
  getJwtSecret(),
  {
    oauth: {
      providers: [
        createAppleProvider({ clientId: 'com.yourapp.id' }),
        createGoogleProvider({ clientId: 'your-client-id.apps.googleusercontent.com' }),
      ],
    },
  }
);

| Handler | Method | Body | Returns | |---------|--------|------|---------| | signup | POST | { email, password, username, displayName } | { token, refreshToken, user } | | signin | POST | { email, password } | { token, refreshToken, user } | | refresh | POST | { refreshToken } | { token, refreshToken } | | oauth | POST | { provider, token } | { token, refreshToken, user } | | verifyToken | — | token string | TokenPayload \| null | | revokeRefreshTokens | — | userId | void |

Defaults: HS256, access TTL 1h, refresh TTL 7d.

OAuth (RS256 + JWKS)

import { verifyOidcToken, createJwksCache } from '@everystack/auth/oauth';

const jwks = createJwksCache({
  fetcher: () => fetch('https://www.googleapis.com/oauth2/v3/certs').then(r => r.json()),
  ttlMs: 3600_000,
});

const claims = await verifyOidcToken(idToken, {
  issuer: ['https://accounts.google.com', 'accounts.google.com'],
  audience: process.env.GOOGLE_CLIENT_ID!,
  jwks,
});

The jwks cache deduplicates inflight fetches and force-refreshes when an unknown kid is seen. Algorithm is pinned to RS256.

Built-in providers (createGoogleProvider, createAppleProvider) wrap the above with the right issuer/JWKS URI and map provider claims to a uniform OAuthUserInfo.

Edge Verification (CloudFront Functions)

CloudFront Functions run a strict ES2019 subset — no Buffer, no TextEncoder, no atob/btoa, no crypto.subtle. Only crypto.createHmac('sha256').digest('base64') is available.

generateCffVerifier() emits a self-contained verifier as a string you can embed in your CFF source:

import { generateCffVerifier } from '@everystack/auth/cff';

const source = generateCffVerifier({
  functionName: 'verifyJwt',
  clockSkewSec: 30,
});

// `source` is portable JS — concatenate into your CFF function file.

The emitted verifyJwt(token, secret) returns { payload } or throws. It pins HS256, requires typ:"JWT", requires numeric exp, and applies clock skew.

For SST users, @everystack/server/cdn provides a higher-level helper:

import { createAuthFunction } from '@everystack/server/cdn';

const auth = createAuthFunction({
  secret: $output(secret.value),
  requireAuth: ['/api/', '!/api/auth/', '!/api/health', '!/api/updates'],
});

new sst.aws.Router('Router', {
  edge: { viewerRequest: { injection: auth.injection } },
});

The injection runs at the edge before any Lambda hop. It returns 401/403 directly when auth fails — no cold start, no API Gateway round trip.

Edge revocation tradeoff

Edge verification trusts the signature; it cannot consult a revocation list without a network call (which defeats the point). Mitigations:

  • Keep access tokens short (≤ 15 min recommended for edge-verified setups)
  • Keep refresh tokens long-lived in DB with revocation
  • Sign-out / password change → revoke refresh tokens, access tokens expire on their own

SQL Twin

@everystack/auth/jwt/sql ships pgcrypto-based functions that produce byte-identical tokens to the JS path:

  • jwt_sign(claims jsonb, secret text)text
  • jwt_verify(token text, secret text)jsonb

Use this if you want PostgREST to mint tokens directly from a sign_in SQL function, or to verify tokens inside RLS policies. Conformance tests guarantee byte-identical output for the same (claims, secret) pair.

Client

import { AuthProvider, useAuth } from '@everystack/auth/client';

function App() {
  return <AuthProvider><YourApp /></AuthProvider>;
}

function Login() {
  const { signIn, signUp, signOut, user, isLoading } = useAuth();
  // ...
}

storage exposes getToken(), getRefresh(), getUser(), save(), clear(). Keys: everystack-token, everystack-refresh, everystack-user.

API Client (@everystack/auth/api)

Pre-configured @everystack/api/client instance:

  • Auto-injects Authorization: Bearer ...
  • On 401 → calls /api/auth/refresh, deduplicates concurrent refreshes, retries original request
  • rpc<T>(name, body?) for /api/rpc/* calls

Password Hashing

  • hashPassword(password) — bcrypt cost 12 (bcryptjs, pure JS). Throws on empty input or >72 UTF-8 bytes (no silent truncation).
  • verifyPassword(password, stored) — accepts $2a$ / $2b$ / $2y$ prefixes; returns false (never throws) on malformed input.
  • SQL twin: byte-compatible with pgcrypto crypt(p, gen_salt('bf', 12)).

Types

interface TokenPayload {
  sub: string;
  email: string;
  role: string;
  // ...your custom claims
}

Peer Dependencies

  • drizzle-orm (optional) — only for @everystack/auth/schema and the high-level handlers
  • react (optional) — only for @everystack/auth/client
  • @everystack/api (optional) — only for @everystack/auth/api

No JWT library dependency.


Part of everystack — a self-hosted application stack for Expo apps on AWS.

License

MIT