Sign-in for Node.
No dependencies.
Sign-up, sign-in by password or emailed link, password resets, and sessions, using only Node's built-in crypto and SQLite. There are no options that turn its protections off.
npm install modest-auth
import { createAuth, createHandler } from "modest-auth";
import { handleNode, toRequest } from "modest-auth";
const auth = createAuth(new DatabaseSync("app.db"));
const handler = createHandler(auth, {
origin: "https://example.org",
linkPage: "/account/link",
sendEmail: yourMailer, // (to, subject, text)
});
createServer(async (req, res) => {
// Sign-up, sign-in, links, and more, at /auth
if (await handleNode(handler, req, res)) return;
const user = handler.userOf(toRequest(req));
res.end(user ? `Hello, ${user.email}` : "Hello");
}).listen(3000);
Signed in: new session
HttpOnly · Secure · __Host- · SameSite=Lax
- 0runtime dependencies
- ~1,950lines of source
- 17routes
- 1SQLite database
Approach
Fewer features, fewer bugs
Many security flaws in authentication come from features and options that combine in ways nobody tested, rather than from the cryptography. modest-auth has few features and no options that weaken it, so there are fewer combinations to get wrong.
Many auth libraries
- Dozens of packages to install
- Plugins and database adapters
- Options that can turn protections off
- Tens of thousands of lines of code
modest-auth
- No packages besides itself
- Node's built-in SQLite only
- No options that weaken it
- About 1,950 lines of code
Signing in
What happens when someone signs in
The routes do all four, so your app doesn't have to.
- Where it came fromRequests from other sites are refused.
- How many triesAttempts are counted per account, per address, and per IPv6 block, before any password is checked.
- The passwordChecked against a scrypt hash. An unknown email takes as long as a wrong password.
- The sessionA new 256-bit token replaces any old one, and only its hash is stored.
Features
What's included
Passwords
Hashed with scrypt at OWASP's recommended cost. New passwords follow NIST's rules: at least 15 characters, and not one of 5,500 common passwords.
Sessions
A session lasts 30 days at most, or 7 days unused. Changing the password ends every other session.
Cross-site protection
Changes must come from your own pages, sent as JSON. Signing in always starts a new session, so a cookie set by someone else is never used.
Rate limits
Stored in the database, so restarting the server doesn't reset them.
Emailed links
Sign up, choose a new password, or sign in by a link that works once and is gone within the hour. Asking for one never shows who has an account.
Tests
Each measure in the threat model has a test that fails if it stops working.
$ npm run check
Rules kept: no dependencies; only node: and own imports; source 2030 lines.
ℹ pass 251
ℹ fail 0
Compatibility
Runs on Node 24 and 26
It also works with any server that uses the standard Request and Response.
- node:http
- Express
- Fastify
- Bun
- Deno
Getting started
npm install modest-auth
It's an early release, and hasn't been independently audited. Please don't use it in production until it has.