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

@cometalabs/better-auth-passwordless

v0.1.8

Published

Passwordless authentication plugin for Better Auth — OTP codes and magic links via email

Readme

🔐 better-auth-passwordless

better-auth-passwordless is a passwordless authentication plugin for Better Auth. It enables login without passwords by sending users a one-time code (OTP) and/or a magic link via email — just like Slack or Linear do it.

Features

  • 🔑 Passwordless login via OTP code or magic link
  • 📧 Single email with both an OTP and a clickable deep link
  • 🔒 Atomic OTP verification to prevent concurrent reuse
  • 🚦 Built-in rate limiting per endpoint
  • 🛡️ Configurable max attempts for both OTP and magic link
  • 🚫 Optional sign-up disable (existing users only)
  • 📦 Full TypeScript support with exported types
  • ⚡️ Works seamlessly as a Better Auth plugin

Installation

npm

npm install @cometalabs/better-auth-passwordless

pnpm

pnpm add @cometalabs/better-auth-passwordless

bun

bun add @cometalabs/better-auth-passwordless

Requires better-auth >= 1.0.0 and zod >= 4.0.0

How it works

  1. User enters their email address
  2. Plugin creates a signed token and an OTP, stores them in the verification table
  3. Your sendEmail function is called with both the OTP and a magic link URL
  4. User either:
    • Clicks the magic link → instantly authenticated via GET /passwordless-bundle/verify
    • Enters the OTP code → authenticated via POST /passwordless-bundle/verify-otp
  5. On success, a session is created and the user is redirected or receives a session token

Usage

Server setup

import { betterAuth } from "better-auth";
import { passwordlessBundle } from "@cometalabs/better-auth-passwordless";
// or from the server subpath:
// import { passwordlessBundle } from "@cometalabs/better-auth-passwordless/server";

export const auth = betterAuth({
  plugins: [
    passwordlessBundle({
      sendEmail: async ({ to, otp, magicLinkUrl, expiresInSeconds, appName }) => {
        // Send your email here using Resend, Nodemailer, etc.
        await resend.emails.send({
          from: "[email protected]",
          to,
          subject: `Your ${appName} login code`,
          html: `
            <p>Your login code is: <strong>${otp}</strong></p>
            <p>Or <a href="${magicLinkUrl}">click here</a> to log in directly.</p>
            <p>Expires in ${expiresInSeconds / 60} minutes.</p>
          `,
        });
      },
    }),
  ],
});

Client setup

import { createAuthClient } from "better-auth/client";
import { passwordlessBundleClient } from "@cometalabs/better-auth-passwordless";
// or from the client subpath:
// import { passwordlessBundleClient } from "@cometalabs/better-auth-passwordless/client";

export const authClient = createAuthClient({
  plugins: [passwordlessBundleClient()],
});

Requesting a login email

await authClient.passwordlessBundle.request({
  email: "[email protected]",
  callbackURL: "/dashboard",         // redirect after magic link login
  newUserCallbackURL: "/onboarding", // redirect for first-time users (optional)
  errorCallbackURL: "/login?error",  // redirect on error (optional)
});

Verifying with OTP

await authClient.passwordlessBundle.verifyOtp({
  email: "[email protected]",
  otp: "123456",
});

Configuration options

passwordlessBundle({
  sendEmail: async (payload, ctx) => { /* required */ },

  expiresInSeconds: 300,       // Token/OTP expiry in seconds (default: 300 = 5 min)
  otpLength: 6,                // Length of the OTP code (default: 6)
  allowedAttemptsOtp: 3,       // Max OTP verification attempts (default: 3)
  allowedAttemptsMagicLink: 1, // Max magic link uses (default: 1)
  disableSignUp: false,        // Block new user creation (default: false)

  rateLimit: {
    windowSeconds: 60,         // Rate limit window (default: 60s)
    max: 5,                    // Max requests per window (default: 5)
  },
})

sendEmail payload

| Field | Type | Description | |-------|------|-------------| | to | string | Recipient email address | | otp | string | The one-time code to display | | magicLinkUrl | string | The full URL for the magic link | | expiresInSeconds | number | Seconds until both expire | | appName | string | Value from betterAuth({ appName }) | | requestMetadata | Record<string, unknown> \| undefined | Extra data passed in the request body |

Endpoints

| Method | Path | Description | |--------|------|-------------| | POST | /passwordless-bundle/request | Send OTP + magic link email | | GET | /passwordless-bundle/verify | Verify magic link token (redirects) | | POST | /passwordless-bundle/verify-otp | Verify OTP code |

Cometa Labs

better-auth-passwordless is built with ☄️ by Cometa Labs.

Source code: github.com/CometaLabs/better-auth-passwordless

Authors

License

MIT - © 2025 Cometa Labs