HBForge
← Back to HBForge

Authentication Shouldn't Need 5 npm Packages

Start a new Node.js project. Add authentication. Here is what your package.json looks like within the hour:

passport passport-local passport-google-oauth20 jsonwebtoken bcryptjs speakeasy express-session connect-redis casl

Nine packages. Nine different APIs. Nine different maintainers, update cycles, and potential vulnerability surfaces. And you still have to wire them together yourself with hundreds of lines of glue code.

We think authentication deserves better.

The Passport Problem

Passport.js is the de facto Node.js authentication library, and it has been for a decade. It works. But its plugin architecture means every authentication method is a separate package. Want Google login? Install passport-google-oauth20. Want GitHub? Install passport-github2. Want local password auth? Install passport-local. There are 500+ strategy packages, each with its own configuration signature.

The result is boilerplate-heavy code that looks something like this: configure passport, write a serialize function, write a deserialize function, configure each strategy separately, mount session middleware, mount passport middleware, write the callback routes. Across our projects, we found the average Passport setup required 180-250 lines of configuration code before a single user could log in.

The NextAuth Trap

NextAuth (now Auth.js) simplified things considerably — for Next.js users. The problem? It couples your authentication to your framework. Migrating from Next.js to SvelteKit, Remix, or a plain Express server means rewriting your entire auth layer. Your session management, your callbacks, your provider configuration — all of it is NextAuth-specific.

Authentication is infrastructure. It should not be locked to a UI framework.

The JWT + bcrypt + 2FA Dance

Even if you skip Passport, you still end up juggling:

Each library has its own error handling patterns, its own configuration format, its own testing strategy. Your authentication "system" is actually five loosely coupled libraries that you maintain the integration for.

forge/auth: One Import, One API

forge/auth — complete setup
import { createAuth } from '@hyperbridge/forge/auth';

const auth = createAuth({
  secret: process.env.AUTH_SECRET,
  providers: {
    google: {
      clientId: process.env.GOOGLE_ID,
      clientSecret: process.env.GOOGLE_SECRET,
    },
    github: {
      clientId: process.env.GITHUB_ID,
      clientSecret: process.env.GITHUB_SECRET,
    },
  },
  jwt: { expiresIn: '15m', refreshExpiresIn: '7d' },
  mfa: { issuer: 'MyApp' },
});

That is the entire configuration. OAuth2 providers, JWT settings, and MFA — all in one object, one import.

Password Hashing with Sensible Defaults

forge/auth — passwords
// Hash with auto-tuned cost factor
const hash = await auth.hashPassword('user-password');

// Verify with constant-time comparison (no timing attacks)
const valid = await auth.verifyPassword('user-password', hash);

// Automatic rehashing when cost factor is outdated
const { valid, rehash } = await auth.verifyPassword(password, hash, {
  autoRehash: true
});
if (rehash) await updateUserHash(userId, rehash);

JWT with Built-in Refresh Rotation

forge/auth — JWT tokens
// Issue access + refresh token pair
const tokens = auth.issueTokens({
  sub: user.id,
  role: user.role,
  permissions: user.permissions,
});
// → { accessToken, refreshToken, expiresAt }

// Verify and decode
const payload = auth.verifyToken(tokens.accessToken);

// Rotate refresh token (old one is invalidated)
const newTokens = await auth.refreshTokens(tokens.refreshToken);

Multi-Factor Authentication

forge/auth — 2FA/MFA
// Generate TOTP secret + QR code data URL
const mfa = auth.generateMFA(user.email);
// → { secret, qrCodeDataURL, backupCodes }

// Verify a TOTP code from authenticator app
const valid = auth.verifyMFA(mfa.secret, '482901');

// Verify a backup code (single-use)
const valid = auth.verifyBackupCode(mfa.backupCodes, 'ABCD-1234-EFGH');

Role-Based Access Control

forge/auth — RBAC
// Define roles and permissions
const rbac = auth.defineRoles({
  admin:  ['users:*', 'posts:*', 'settings:*'],
  editor: ['posts:read', 'posts:write', 'posts:delete'],
  viewer: ['posts:read'],
});

// Check permissions anywhere
if (rbac.can(user.role, 'posts:delete')) {
  await deletePost(postId);
}

// Middleware for route protection
app.delete('/api/posts/:id',
  auth.requireAuth(),
  auth.requirePermission('posts:delete'),
  deleteHandler
);

Magic Links

forge/auth — passwordless login
// Send a magic link (generates signed, time-limited URL)
const link = auth.createMagicLink({
  email: 'user@example.com',
  redirectTo: '/dashboard',
  expiresIn: '15m',
});
// → https://myapp.com/auth/verify?token=eyJhbG...

// Verify when user clicks
const session = await auth.verifyMagicLink(token);
// → { user, tokens, redirectTo }

What You Actually Ship

With Passport and friends, your authentication code is scattered across middleware files, strategy configurations, session stores, and route handlers. With forge/auth, your entire auth system is one object with a consistent API.

Compare the dependency surface:

passport (6 deps) passport-google-oauth20 (3 deps) jsonwebtoken (5 deps) bcryptjs (0 deps, C++ binding) speakeasy (4 deps)

vs.

@hyperbridge/forge/auth (0 deps)

Zero dependencies means zero supply chain risk. No left-pad moments. No event-stream attacks. No hidden sub-dependency with a critical CVE that you discover in production at 2 AM.

Framework Agnostic by Design

forge/auth works with Express, Fastify, Hono, Koa, or no framework at all. It works in Node.js, Deno, Bun, and Cloudflare Workers. Your auth configuration is portable because it does not depend on any framework's middleware system. Switch from Express to Hono? Your auth code stays the same. Deploy to the edge? It just works — no binary dependencies to worry about.

Authentication is too important to scatter across five packages maintained by five different people with five different release schedules. It should be one coherent system with one API, one set of documentation, and one team responsible for keeping it secure.

HBForge is currently available exclusively for enterprise clients. Opening to the Developer Community on June 25, 2026.

Contact kr@hyperbridge.in for early access.