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

@kuratchi/auth

v0.0.4

Published

Config-driven auth for KuratchiJS — credentials, OAuth, RBAC, rate limiting, Turnstile

Readme

@kuratchi/auth

The Kuratchi quickstart auth library. Pick this when you want a working credentials-based auth in five minutes — signup, signin, sessions, role-based permissions, rate limiting, OAuth, Turnstile bot protection — all driven by a single config object.

What this is

A starter, not a standard. @kuratchi/auth is opinionated, batteries-included, and tightly scoped to D1-backed apps. It gets you to "users can log in" fast. If you outgrow it (federated identity, complex authorization graphs, custom session backends), swap it out — the framework doesn't depend on it.

What this is not

  • The auth library you should use for everything. For production apps with serious requirements, evaluate Auth.js with a Workers adapter, Lucia, WorkOS, Clerk, or your own implementation.
  • A framework feature. @kuratchi/js doesn't know @kuratchi/auth exists. The integration point is a regular middleware step, just like any third-party auth library would have.
  • Cloudflare Access. Access is the platform's edge identity layer and lives in @kuratchi/js/access because it's a framework primitive (no DB, no sessions, no schemas — just JWT verification). The two compose orthogonally — see Composing with Cloudflare Access below.

If "starter, not standard" feels too small, that's the signal to use something else. The framing matters because:

  • It keeps @kuratchi/auth simple. We don't have to support every SSO + MFA + WebAuthn flow under the sun.
  • It keeps the framework decoupled. Swapping auth libraries shouldn't require a rewrite.
  • It sets honest expectations. You're using a quickstart, not a battle-hardened identity platform.

Install

npm install @kuratchi/auth @kuratchi/orm

Wire it up

For KuratchiJS, the primary adapter is @kuratchi/auth/kuratchi-js. Auth is still composed at middleware time, not declared in kuratchi.config.ts.

// src/server/auth-config.ts
import { kuratchiAuthConfig } from '@kuratchi/auth/adapter';

export const authConfig = kuratchiAuthConfig({
  cookieName: 'kuratchi_session',
  sessionEnabled: true,
  csrf: {
    paths: ['/auth/signin', '/auth/signup'],
    trustedOrigins: ['https://app.example.com'],
  },
  guards: {
    paths: ['/*'],
    exclude: ['/auth/signin', '/auth/signup', '/api/public/*'],
    redirectTo: '/auth/signin',
  },
});
// src/middleware.ts
import { defineMiddleware } from '@kuratchi/js';
import { initKuratchiAuth } from '@kuratchi/auth/kuratchi-js';
import { authConfig } from '$server/auth-config';

const auth = initKuratchiAuth(authConfig);

export default defineMiddleware({
  auth: auth.middleware(),
});

That is the primary KuratchiJS integration point. @kuratchi/auth/middleware remains available as the lower-level compatibility path.

Common APIs

import {
  // sessions + sign-up/sign-in
  signUp, signIn, signOut, getCurrentUser, getAuth,

  // password reset
  requestPasswordReset, resetPassword,

  // email verification
  verifyEmail, resendEmailVerification,

  // organization invitations (org-mode)
  inviteMember, acceptInvite,

  // activity, RBAC, OAuth, guards, turnstile
  logActivity, getActivity,
  hasRole, hasPermission, assignRole,
  startOAuth, handleOAuthCallback,
  requireAuthGuard, verifyTurnstile,

  // org-DO helpers (used by your custom resolvers)
  getOrgClient, getOrgStubByName, resolveOrgDatabaseName, isOrgAvailable,

  // schema table maps to spread into your ORM schemas
  authAdminTables, authOrgTables,
} from '@kuratchi/auth';

All of these read from request-scoped locals populated by kuratchiAuthMiddleware. Call them from route handlers, actions, RPC functions — the auth context is available wherever the framework runs request code.

Feature areas

  • Credentials: signup, signin, signout, current user, password reset.
  • Email verification: optional sendVerificationEmail callback; requireEmailVerified blocks signin until the user clicks the link; verifyEmail() / resendEmailVerification() form-actions.
  • Invitations (org-mode): inviteMember() creates a placeholder user inside the org's DO + an organizationUsers mapping + an invite token. acceptInvite() finishes the flow.
  • Organizations (multi-tenant): one Durable Object per org. The package routes credential/session ops to the right DO via getOrgStubByName(doName). Admin D1 keeps only the email→org index. See Organizations and Schema and the reference implementation in apps/web/src/server/auth.do.ts.
  • Activity logging: structured audit trail with optional severity / category metadata.
  • Roles and permissions: define role → permission maps; check via hasRole / hasPermission.
  • OAuth providers: opinionated integrations for Google, GitHub.
  • Route guards: declarative path-based authentication redirects.
  • CSRF and origin checks: opt-in Fetch Metadata and Origin validation for credential POST routes.
  • Rate limiting: per-route throttling backed by a KV namespace.
  • Turnstile: Cloudflare bot-check verification on protected routes.

Schema

Spread the package's table maps into your ORM schemas:

// src/server/schemas/admin.ts (single-tenant: keep all auth tables here)
import { authAdminTables } from '@kuratchi/auth';

export const adminSchema = {
  name: 'admin',
  tables: {
    ...authAdminTables,
    // your app tables
  },
};

For org-mode you split into two schemas — admin keeps organizations + organizationUsers + emailVerifications, the per-org DO holds users + sessions + passwordResets. See the Organizations and Schema docs for the canonical split.

Org-mode at a glance

// src/server/auth-config.ts
export const authConfig = kuratchiAuthConfig({
  credentials: { binding: 'DB', requireEmailVerified: true,
    sendVerificationEmail: async ({ email, token }) => { /* ... */ },
    sendInviteEmail:       async ({ email, token, invitedBy }) => { /* ... */ },
  },
  organizations: { binding: 'ORG_DB' },  // ← turns org-mode on
});
// src/server/auth.do.ts — the per-org DO. You write this; the package calls into it.
import { kuratchiDO } from '@kuratchi/js';
import { autoMigrate, kuratchiORM } from '@kuratchi/orm';
import { orgSchema } from './schemas/org';

export default class OrgAuth extends kuratchiDO {
  static binding = 'ORG_DB';
  declare ctx: DurableObjectState;
  declare env: any;

  constructor(ctx: DurableObjectState, env: any) {
    super();
    this.ctx = ctx;
    this.env = env;
    autoMigrate(ctx.storage, orgSchema);
    this.db = kuratchiORM(ctx.storage.sql, orgSchema);
  }

  async createUser(input)        { /* implements the auth contract */ }
  async getUserByEmail(email)    { /* ... */ }
  async getUserById(id)          { /* ... */ }
  async createSession(input)     { /* ... */ }
  async getSession(tokenHash)    { /* ... */ }
  async deleteSession(tokenHash) { /* ... */ }
  async markEmailVerified(userId)         { /* ... */ }
  async completeInvite({ userId, passwordHash, name }) { /* ... */ }
}

The framework auto-discovers *.do.ts files and adds the matching binding + SQLite migration to wrangler.jsonc.

Secrets

Set auth-related secrets via Worker env/secrets (e.g. AUTH_SECRET, OAuth provider secrets, Turnstile secret). The middleware factory reads them from the request's bound env at runtime.

Composing with Cloudflare Access

@kuratchi/auth and Cloudflare Access answer different questions:

  • Cloudflare Access = "is this user from my org?" Verified at the edge against your IdP. Lives in @kuratchi/js/access.
  • @kuratchi/auth = "is this app user signed in?" Verified against your D1 database. Lives here.

For an admin panel where employees log into an app that customers also use, you can compose both:

// src/middleware.ts
import { defineMiddleware } from '@kuratchi/js';
import { requireCloudflareAccess } from '@kuratchi/js/access';
import { kuratchiAuthMiddleware } from '@kuratchi/auth/middleware';
import { authConfig } from '$server/auth-config';

export default defineMiddleware({
  // Edge-level identity: only employees with Access policies can hit /admin
  access: requireCloudflareAccess({
    audience: env.CF_ACCESS_AUD,
    teamDomain: 'mycompany.cloudflareaccess.com',
    exclude: ['/api/public/*', '/auth/*', '/'],
  }),
  // App-level identity: customers sign in to the public app via credentials
  auth: kuratchiAuthMiddleware(authConfig),
});

The two are independent — neither depends on the other.

When to swap this out

Reasonable signals to outgrow @kuratchi/auth:

  • You need WebAuthn / passkeys.
  • You need federated identity beyond the included OAuth providers (e.g. SAML, OIDC against arbitrary providers).
  • You want sessions in something other than D1 (Redis, JWT, KV).
  • You need fine-grained permission graphs beyond role → permission lists.
  • You need MFA, magic links beyond email, or device-based session pinning.
  • Your team prefers a battle-tested third-party for security-critical surface area.

When that day comes: replace the kuratchiAuthMiddleware step with whatever you're swapping to, drop @kuratchi/auth from your deps, and the rest of your app keeps working. That's the whole point of the middleware-only integration — it's the same kind of seam Express / Hono / Next.js give you.