awesome-node-auth

April 29, 2026 · View on GitHub

npm version license github stars

NPM

A production-ready, database-agnostic JWT authentication library for Node.js written in TypeScript. Drop-in auth for Express, NestJS, Next.js, Fastify and any other Node.js framework — connect to any database through a single interface.

The self-hosted alternative to Supertokens and Supabase Auth. Same enterprise-grade features, zero vendor lock-in.


Installation

npm install awesome-node-auth

Quick Start

import express from 'express';
import { AuthConfigurator } from 'awesome-node-auth';
import { myUserStore } from './my-user-store'; // your IUserStore impl

const app = express();
app.use(express.json());

const auth = new AuthConfigurator(
  {
    accessTokenSecret: process.env.ACCESS_TOKEN_SECRET!,
    refreshTokenSecret: process.env.REFRESH_TOKEN_SECRET!,
    accessTokenExpiresIn: '15m',
    refreshTokenExpiresIn: '7d',
  },
  myUserStore,
);

app.use('/auth', auth.router());  // mounts all auth endpoints

app.get('/protected', auth.middleware(), (req, res) => {
  res.json({ user: req.user });
});

app.listen(3000);

Implement IUserStore once for your database and you're done.
Full DB examples (MongoDB, PostgreSQL, MySQL, in-memory) → README.detailed.md.


Features

AreaHighlights
Auth strategiesEmail/password · OAuth 2.0 (Google, GitHub, custom) · Magic links · SMS OTP · TOTP 2FA
Token managementHttpOnly-cookie or Bearer mode · automatic access/refresh rotation · __Host-/__Secure- cookie prefixes
Identity Provider (IdP) mode (v1.9)RS256-signed JWTs · public JWKS endpoint (/.well-known/jwks.json) · Resource Server middleware · zero new dependencies
Stateful sessions (v1.5)ISessionStore + real-time revocation (checkOn: allcalls|refresh|none) · L1/L2 caching decorators
Dynamic email templates (v1.6)ITemplateStore — per-language mail templates + UI i18n with safe hardcoded fallback · built-in MemoryTemplateStore
CSRF protectionDouble-submit cookie pattern · __Host- prefix hardening against cookie-tossing
Account managementRegistration · change email/password · account deletion · email verification (none/lazy/strict)
Account linkingLink multiple OAuth providers · conflict resolution via IPendingLinkStore
RBACIRolesPermissionsStore with tenant awareness
Multi-tenancyITenantStore for isolated tenant apps
Admin panelFull-featured admin UI: user management, sessions, roles, tenants, metadata, API keys, webhooks
Built-in UIZero-dependency HTML/CSS/JS login UI served at <apiPrefix>/ui/ · headless mode for SPAs
Client librariesng-awesome-node-auth (Angular) · awesome-node-auth-flutter (Flutter/Dart)
Event-drivenAuthEventBus · SSE push · inbound/outbound webhooks · telemetry
API keysM2M bcrypt-hashed keys with scopes, expiry, IP allowlist and audit log
OpenAPI / SwaggerAuto-generated specs for auth, admin and tools routers
MCP serverawesome-node-auth-mcp-server — Cursor/VS Code integration for code generation

Identity Provider (IdP) Mode (v1.9)

Turn any Provisioner into a central IdP that issues RS256-signed JWTs. Downstream Resource Servers validate tokens via the public JWKS endpoint — no shared secrets.

Generate the RSA private key for your .env (uses Node.js built-in crypto — no install needed):

node -e "
const { generateKeyPairSync } = require('crypto');
const { privateKey } = generateKeyPairSync('rsa', { modulusLength: 2048 });
const pem = privateKey.export({ type: 'pkcs8', format: 'pem' });
console.log('IDP_PRIVATE_KEY=' + Buffer.from(pem).toString('base64'));
"

Then in your config:

// Provisioner (IdP)
const auth = new AuthConfigurator({
  accessTokenSecret: '...',
  refreshTokenSecret: '...',
  idProvider: {
    enabled: true,
    issuer: 'https://auth.myplatform.com',
    privateKey: Buffer.from(process.env.IDP_PRIVATE_KEY!, 'base64').toString('utf8'),
  },
}, userStore);

// Resource Server (downstream)
import { createJwksAuthMiddleware } from 'awesome-node-auth';

app.use('/api', createJwksAuthMiddleware({
  jwksUrl: 'https://auth.myplatform.com/.well-known/jwks.json',
  issuer:  'https://auth.myplatform.com',
}), myApiRouter);

In development, if you omit privateKey an ephemeral keypair is auto-generated at startup.

→ Full guide: awesomenodeauth.com/docs/advanced/idp-mode


Key Endpoints

POST   /auth/login              POST /auth/refresh           GET  /auth/me
POST   /auth/register           POST /auth/logout            GET  /auth/sessions        ← device list
POST   /auth/forgot-password    POST /auth/change-password   DELETE /auth/sessions/:h   ← revoke device
POST   /auth/magic-link/send    POST /auth/2fa/verify        DELETE /auth/account
GET    /auth/oauth/:provider    GET  /auth/oauth/:provider/callback
POST   /auth/sessions/cleanup   POST /auth/add-phone         PATCH /auth/profile
GET    /.well-known/jwks.json                                                            ← IdP mode only

Optional Stores Snapshot

const auth = new AuthConfigurator(config, userStore, {
  sessionStore,      // ISessionStore       — stateful sessions + device management
  metadataStore,     // IUserMetadataStore  — arbitrary per-user key/value pairs
  rbacStore,         // IRolesPermissionsStore
  tenantStore,       // ITenantStore
  pendingLinkStore,  // IPendingLinkStore   — OAuth account-linking conflicts
  templateStore,     // ITemplateStore      — dynamic email templates + UI i18n (v1.6)
});

Full configuration reference → README.detailed.md § Configuration


Documentation

ResourceLink
Full referenceREADME.detailed.md
Wiki / Guidesawesomenodeauth.com
ChangelogCHANGELOG.md
MCP servermcp-server/README.md
Demo appsdemo/
Framework examplesexamples/

License

MIT · © 2026 nik2208 · Sponsor ❤