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

bezzie

v1.0.2

Published

BFF OAuth 2.0 auth library for Cloudflare Workers

Readme

Bezzie

Your BFF's BFF. OAuth for Cloudflare Workers + Hono, done the safe way.

If you followed Auth0's SPA guide, your access token lives in the browser — in memory, in a Web Worker, or in localStorage. Any script that runs on your page can reach it. That's not a criticism of Auth0; it's just the default SPA pattern, and it's the one BCP 212 now recommends against.

Bezzie moves the OAuth flow into your Cloudflare Worker. Tokens stay server-side in KV. The browser gets an HttpOnly; Secure; SameSite session cookie — unreadable by JavaScript, unavailable to XSS. Your frontend code gets simpler, not more complicated.

app.route('/auth', auth.routes())       // login, callback, logout
app.use('/api/*', auth.middleware())    // protect routes — user available as c.var.user

npm version npm downloads license GitHub


Get started in 5 minutes

1. Install:

npm install bezzie

2. Add a KV namespace to wrangler.toml:

[[kv_namespaces]]
binding = "SESSION_KV"
id = "<your-kv-namespace-id>"

3. Add your client secret:

wrangler secret put AUTH0_CLIENT_SECRET

4. Wire it up:

import { createBezzie, providers, cloudflareKVAdapter } from 'bezzie'

const auth = createBezzie({
  ...providers.auth0('your-tenant.auth0.com'),
  clientId: 'xxx',
  clientSecret: env.AUTH0_CLIENT_SECRET,
  adapter: cloudflareKVAdapter(env.SESSION_KV),
  baseUrl: 'https://app.yourproject.com',
})

app.route('/auth', auth.routes())
app.use('/api/*', auth.middleware())

5. Protect a route:

app.get('/api/me', (c) => c.json(c.var.user))

Done. Your app now has BCP212-compliant BFF auth.


Demo

See the full BFF flow in action: bezzie-demo.neilmason.dev

Source: github.com/neilpmas/bezzie-demo


Why

There's no open source library for this specific combination (BFF OAuth on Cloudflare Workers). The closest alternatives are Duende BFF (.NET) and @auth0/nextjs-auth0 — both tied to specific frameworks and neither running at the edge.

Bezzie is framework-agnostic, Workers-native, and ships with adapters for Cloudflare KV, Redis (including Upstash), and in-memory storage.


Usage

import { createBezzie, providers, cloudflareKVAdapter } from 'bezzie'

const auth = createBezzie({
  ...providers.auth0('your-tenant.auth0.com'),
  clientId: 'xxx',
  clientSecret: env.AUTH0_CLIENT_SECRET,
  audience: 'https://api.yourproject.com',
  adapter: cloudflareKVAdapter(env.SESSION_KV),
  baseUrl: 'https://app.yourproject.com',
})

// Mount auth routes
app.route('/auth', auth.routes())

// Protect API routes
app.use('/api/*', auth.middleware())

This gives you:

| Route | Description | |---|---| | GET /auth/login | Redirects to provider, initiates Authorization Code + PKCE flow. Supports returnTo query param for post-login redirect. | | GET /auth/callback | Exchanges code for tokens, stores session in KV, sets cookie. | | POST /auth/logout | Clears session, clears cookie, redirects to provider logout. |


Accessing User Identity

After auth.middleware(), downstream handlers can access the user identity and the current access token via c.var:

app.get('/api/me', (c) => {
  const user = c.var.user
  const token = c.var.accessToken
  return c.json({ user })
})

Forwarding Upstream

The accessToken on the context is intended for the app to forward to an upstream service (e.g., a Spring Boot API or any other microservice), since Bezzie doesn't mutate request headers directly.

app.all('/api/proxy/*', async (c) => {
  const url = new URL(c.req.url)
  const target = `https://api.upstream.com${url.pathname}${url.search}`
  
  return fetch(target, {
    method: c.req.method,
    headers: {
      ...c.req.header(),
      'Authorization': `Bearer ${c.var.accessToken}`
    },
    body: c.req.raw.body
  })
})

How It Works

System context

C4Context
  title System Context — Bezzie

  Person(user, "User", "Browser application user")
  System(bezzie, "Cloudflare Worker (bezzie)", "BFF: owns the OAuth flow, issues session cookies to the browser")
  System_Ext(idp, "Identity Provider", "Auth0 / Okta / Keycloak / Google — issues tokens")
  System_Ext(upstream, "Upstream API", "Your backend — trusts Bearer tokens forwarded by the Worker")

  Rel(user, bezzie, "HTTPS requests + session cookie")
  Rel(bezzie, idp, "OIDC discovery, token exchange, token refresh")
  Rel(bezzie, upstream, "Proxied requests with Authorization: Bearer")
  Rel(idp, user, "Redirect back after login")

Containers

C4Container
  title Container — bezzie deployment

  Person(user, "User")
  Container(spa, "React SPA", "Cloudflare Pages", "Public landing page + protected dashboard")
  Container(worker, "Cloudflare Worker", "Hono + bezzie", "BFF: auth routes + request middleware + token management")
  ContainerDb(kv, "Cloudflare KV", "KVNamespace", "Stores sessions and PKCE state")
  System_Ext(idp, "Identity Provider", "Auth0 / Okta / Keycloak")
  System_Ext(upstream, "Upstream API", "Backend services")

  Rel(user, spa, "HTTPS")
  Rel(spa, worker, "API calls + __Host-session cookie")
  Rel(worker, kv, "Session read / write / delete")
  Rel(worker, idp, "OIDC discovery + token exchange + token refresh + JWKS")
  Rel(worker, upstream, "Authorization: Bearer {accessToken}")

Per-request flow

  1. Browser sends request to BFF with session cookie
  2. BFF looks up session in KV, retrieves access token
  3. BFF validates JWT (via JWKS, using Web Crypto API)
  4. If expired, BFF uses refresh token to get a new one and updates KV
  5. BFF forwards request upstream with Authorization: Bearer <token>

Adapters

Bezzie supports multiple session storage backends:

Cloudflare KV

Recommended for production on Cloudflare Workers.

import { cloudflareKVAdapter } from 'bezzie'
// ...
adapter: cloudflareKVAdapter(env.SESSION_KV)

Redis (Upstash)

Good for cross-region session consistency. Works with Upstash Redis (recommended for Cloudflare Workers) and any Redis client with get/set/del methods.

import { redisAdapter } from 'bezzie'
import { Redis } from '@upstash/redis/cloudflare'

adapter: redisAdapter(new Redis({
  url: env.UPSTASH_REDIS_REST_URL,
  token: env.UPSTASH_REDIS_REST_TOKEN,
}))

Memory

Useful for local development and testing. Do not use in production.

import { MemoryAdapter } from 'bezzie'
// ...
adapter: new MemoryAdapter()

Configuration

| Option | Type | Description | |---|---|---| | issuer | string | Your OIDC provider issuer URL (e.g. https://tenant.auth0.com) | | clientId | string | OAuth client ID | | clientSecret | string | OAuth client secret — keep in Workers secrets | | audience | string | API audience identifier | | adapter | SessionAdapter | Session adapter (e.g. cloudflareKVAdapter(env.SESSION_KV)) | | baseUrl | string | Base URL of your application (used for callback and redirects) | | providerOverrides | object | Hard overrides for specific provider values (logoutUrl, tokenEndpoint) |


Cloudflare Setup

Add a KV namespace to your wrangler.toml:

[[kv_namespaces]]
binding = "SESSION_KV"
id = "<your-kv-namespace-id>"

Add your client secret as a Workers secret:

wrangler secret put AUTH0_CLIENT_SECRET

Alternatives

| | Bezzie | Auth.js (NextAuth) | Lucia | Roll your own (oauth4webapi) | |---|---|---|---|---| | BFF pattern (tokens never in browser) | ✅ | ✅ (some adapters) | ❌ | You decide | | Cloudflare Workers native | ✅ | ⚠️ Edge adapter | ⚠️ | ✅ | | Hono integration | ✅ | ❌ | ❌ | ✅ | | OIDC discovery | ✅ | ✅ | ❌ | ✅ | | Token refresh | ✅ | ✅ | Manual | Manual | | Pluggable session storage | ✅ (KV, Redis, Memory) | ✅ | ✅ | Manual | | Zero Node.js deps | ✅ | ❌ | ✅ | ✅ |


Stack

| Component | Choice | |---|---| | Runtime | Cloudflare Workers | | Router | Hono | | OAuth | oauth4webapi (spec-compliant, no Node.js deps) | | Session storage | Cloudflare KV |


Status

v1.0.1 — stable


Changelog

See CHANGELOG.md for release history.


License

MIT