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

@deeblr/auth

v0.4.0

Published

Deeblr Auth meta-package: a complete, batteries-included authentication facade (registration, login, password management, email verification, account deletion, framework-agnostic middleware) built on @deeblr/auth-core.

Readme

@deeblr/auth

The complete, batteries-included Deeblr Auth facade: registration, login, password management (change/forgot/reset), email verification, account deletion, and framework-agnostic middleware — all built on top of @deeblr/auth-core.

Install

npm install @deeblr/auth

Quick start

import { DeeblrAuth } from "@deeblr/auth";
import { myAdapter } from "./my-adapter";

const auth = new DeeblrAuth({
  adapter: myAdapter,
  secret: process.env.AUTH_SECRET!, // >= 16 chars, e.g. `openssl rand -base64 32`
});

const user = await auth.register({
  email: "[email protected]",
  password: "correct-horse-battery-staple",
  name: "Ada Lovelace", // custom fields are supported
});

const { user: loggedIn } = await auth.login({
  email: "[email protected]",
  password: "correct-horse-battery-staple",
});

Configuration

new DeeblrAuth({
  adapter,                 // required — a DatabaseAdapter (see @deeblr/auth-core)
  secret: "...",           // required — signs password-reset / email-verification tokens
  password: {              // optional password policy (all default to permissive)
    minLength: 10,
    requireUppercase: true,
    requireLowercase: true,
    requireNumbers: true,
    requireSymbols: true,
  },
  tokens: {
    passwordResetMinutes: 30,      // default 30
    emailVerificationMinutes: 1440, // default 24h
  },
  requireEmailVerification: false, // if true, login() throws EmailNotVerifiedError until verified
  plugins: [],                     // any @deeblr/auth-core plugin
  logger, emailAdapter, security,  // pass-through to @deeblr/auth-core
});

Public API

| Method | Description | |---|---| | register(input) | Creates a user. Supports custom fields beyond email/password. Returns the user directly. | | login(input) | Authenticates by email/password. Checks account state (disabled/lockedUntil) and, if configured, email verification, before delegating to core. Returns { user, session? }. | | logout(input) | Ends a session. Strategy-agnostic — works the same with no session plugin, a future @deeblr/auth-session, or @deeblr/auth-jwt. | | user(id) | Retrieves a user by id. Throws UserNotFoundError. | | changePassword(input) | Verifies the current password, validates the new one against policy, updates it. | | forgotPassword({ email }) | Issues a signed reset token and emails it. Never reveals whether the email exists. | | resetPassword({ token, newPassword }) | Verifies the token and updates the password. | | requestEmailVerification({ userId }) | Issues a signed verification token and emails it. | | verifyEmail({ token }) | Verifies the token and marks the account verified. | | deleteAccount({ userId }) | Deletes the account. Emits auth:beforeDeleteAccount / auth:afterDeleteAccount. | | isAuthenticated(context) | Pure check on an already-resolved AuthContext. | | forRequest(context) | Returns a request-scoped { user(), isAuthenticated(), logout() } — genuinely zero-argument and safe under concurrency (see below). | | use(plugin), hooks, services, state, initialize(), destroy(), core | Pass through to the underlying DeeblrAuthCore. |

Why no zero-argument auth.user() / auth.isAuthenticated()?

A single DeeblrAuth instance is shared across every concurrent request in a real server. A "current user" stored directly on that instance would leak between requests — that's a correctness bug, not an ergonomics trade-off worth taking. Instead:

// A session/JWT strategy plugin (or, for now, your own resolver) produces
// an AuthContext per request:
const context = await resolveAuthContext(request); // { user, session? }

// Then you get genuinely zero-argument, request-scoped calls:
const requestAuth = auth.forRequest(context);
await requestAuth.user();
requestAuth.isAuthenticated();
await requestAuth.logout();

This is also the seam @deeblr/auth-express / @deeblr/auth-nextjs will build on: they'll construct the AuthContext per request and attach auth.forRequest(context) to req.auth (or equivalent) automatically.

Middleware

import { createAuthMiddleware } from "@deeblr/auth";

// `resolver` is supplied by a session/JWT strategy plugin once one exists.
// This package ships the factory, not a resolver — there's nothing to
// resolve a session/token FROM without one of those installed yet.
const middleware = createAuthMiddleware(resolver, { required: true });

const context = await middleware({ headers: request.headers });

Hooks and events

Every flow emits on auth.hooks, which is the exact same HookBus as @deeblr/auth-core. Two naming styles are both live:

  • Colon-namespaced (from core, extended here): auth:beforeRegister, auth:afterRegister, auth:beforeLogin, auth:afterLogin, auth:beforeLogout, auth:afterLogout, auth:beforeDeleteAccount, auth:afterDeleteAccount, auth:passwordChanged, auth:passwordResetRequested, auth:passwordReset, auth:emailVerificationRequested, auth:emailVerified.
  • Dot-notation domain events (this package): user.registered, user.login, user.logout, user.deleted, password.changed, password.reset, email.verified — re-emitted on the same bus whenever the corresponding auth:* hook fires, so either naming style works.
auth.hooks.on("user.registered", async ({ user }) => {
  await sendWelcomeEmail(user);
});

Errors

All errors extend AuthError and carry a stable code. New in this package: EMAIL_NOT_VERIFIED, PASSWORD_TOO_WEAK, ACCOUNT_DISABLED, ACCOUNT_LOCKED, INVALID_RESET_TOKEN (plus everything already in @deeblr/auth-core: INVALID_CREDENTIALS, USER_ALREADY_EXISTS, USER_NOT_FOUND, etc).

Password reset / email verification tokens

Reset and verification links use signed, stateless HMAC-SHA256 tokens — nothing is persisted, so no database schema changes are required. The trade-off: a token can't be individually revoked before its TTL expires (default 30 minutes for reset, 24 hours for verification). A future @deeblr/auth-security denylist is the natural place to add single-use revocation later without changing this format.

License

MIT