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

@developersailor/express-auth

v1.0.2

Published

Secure, flexible authentication package for Express.js with JWT, refresh tokens, and role-based access control

Downloads

327

Readme

@developersailor/express-auth

Secure, flexible authentication package for Express.js with JWT, refresh tokens, and role-based access control.

npm version License: MIT

See CHANGELOG.md for release notes and migration guidance.

Features

  • 🔐 JWT Authentication - Secure access tokens with configurable expiration
  • 🔄 Refresh Token Rotation - Secure refresh token handling with automatic rotation
  • 👤 Role-based Access Control - Fine-grained permission system
  • 🗄️ Repository Pattern - Database-agnostic design (bring your own ORM)
  • 📝 TypeScript - Full type safety and IntelliSense support
  • 🧪 Test Adapters - Built-in memory adapters for testing
  • 🍪 Cookie Support - Secure httpOnly cookie handling
  • 🎨 Decorators - Metadata decorators for route protection
  • 🚀 Production Ready - Security best practices built-in

Installation

npm install @developersailor/express-auth

Peer dependencies:

npm install express reflect-metadata

Quick Start

import 'reflect-metadata';
import express from 'express';
import { createAuthRouter, createAuthMiddleware, JWTService } from '@developersailor/express-auth';

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

// Create auth router with your configuration
const authRouter = createAuthRouter({
  jwtSecret: process.env.JWT_SECRET!,
  refreshTokenSecret: process.env.REFRESH_TOKEN_SECRET!,
  repositories: {
    userRepository: myUserRepository,
    refreshTokenRepository: myRefreshTokenRepository,
  },
});

app.use('/auth', authRouter);

// Protect routes
const jwtService = new JWTService({
  jwtSecret: process.env.JWT_SECRET!,
  refreshTokenSecret: process.env.REFRESH_TOKEN_SECRET!,
});

const authMiddleware = createAuthMiddleware(jwtService);

app.get('/api/protected', authMiddleware, (req, res) => {
  res.json({ message: 'This is protected' });
});

Core Concepts

Repository Pattern

This package uses the repository pattern, meaning you bring your own database implementation:

import { UserRepository, RefreshTokenRepository, AuthUser } from '@developersailor/express-auth';

// Implement the interfaces with your ORM (Prisma, TypeORM, etc.)
class PrismaUserRepository implements UserRepository {
  async findByEmail(email: string): Promise<AuthUser | null> {
    // Your implementation
  }
  
  async findById(id: string): Promise<AuthUser | null> {
    // Your implementation
  }
  
  async createUser(data: { email: string; passwordHash: string }): Promise<AuthUser> {
    // Your implementation
  }
}

Security Best Practices

This package follows security best practices:

  • No secrets in code - All secrets passed via configuration
  • Strong password hashing - bcrypt with configurable rounds
  • Token rotation - Refresh tokens are rotated on each use
  • Hashed refresh token storage - Refresh tokens are hashed before persistence by default
  • Generic error messages - No information leakage
  • JWT best practices - Algorithm explicitly set to HS256
  • Secure by default - Secure cookie settings

API Endpoints

The createAuthRouter creates the following endpoints:

| Method | Endpoint | Description | Auth Required | |--------|----------|-------------|---------------| | POST | /auth/register | Register new user | No | | POST | /auth/login | Login and get tokens | No | | POST | /auth/refresh | Refresh access token | No | | POST | /auth/logout | Logout (revoke token) | No | | POST | /auth/logout-all | Logout all devices | Yes | | GET | /auth/me | Get current user | Yes |

Configuration

interface AuthConfig {
  // Required: JWT secrets (from environment variables)
  jwtSecret: string;
  refreshTokenSecret: string;
  
  // Optional: Token expiration
  accessTokenExpiresIn?: string | number;  // default: '15m'
  refreshTokenExpiresIn?: string | number; // default: '7d'
  
  // Required: Repositories
  repositories: {
    userRepository: UserRepository;
    refreshTokenRepository: RefreshTokenRepository;
  };

  // Optional: Registration configuration
  registration?: {
    defaultRoles?: string[];           // Default: ['user']
    allowRolesFromRequest?: boolean;   // Default: false
  };

  // Optional: Hash refresh tokens before repository storage
  // Default: true
  // Migration note: enabling this for apps with existing raw refresh token
  // records will require users to log in again.
  hashRefreshTokens?: boolean;
  
  // Optional: Authorization configuration
  authorization?: {
    getRoles?: (user: AuthUser) => string[];           // Default: (u) => u.roles || []
    getPermissions?: (user: AuthUser) => Permission[]; // Default: (u) => u.permissions || []
    loadUserOnRequest?: boolean;                       // Default: false
    userCacheTTL?: number;                             // Default: 60 (seconds)
    ownershipBypassRoles?: string[];                   // Default: ['admin']
    hierarchicalPermissions?: boolean;                 // Default: false
  };
  
  // Optional: Cookie settings
  cookie?: {
    httpOnly?: boolean;
    secure?: boolean;
    sameSite?: 'strict' | 'lax' | 'none';
    domain?: string;
    path?: string;
  };
  
  // Optional: Password validation rules
  passwordRules?: {
    minLength?: number;
    requireUppercase?: boolean;
    requireLowercase?: boolean;
    requireNumbers?: boolean;
    requireSpecialChars?: boolean;
  };
  
  // Optional: Custom error messages
  errorMessages?: {
    invalidCredentials?: string;
    unauthorized?: string;
    forbidden?: string;
    tokenExpired?: string;
    invalidToken?: string;
  };
}

Middleware

Authentication Middleware

import { createAuthMiddleware, JWTService } from '@developersailor/express-auth';

const jwtService = new JWTService({
  jwtSecret: process.env.JWT_SECRET!,
  refreshTokenSecret: process.env.REFRESH_TOKEN_SECRET!,
});

const authMiddleware = createAuthMiddleware(jwtService);

// Protect a route
app.get('/api/protected', authMiddleware, handler);

Role-based Middleware

import { requireRoles, requireAllRoles } from '@developersailor/express-auth';

// Require any of the roles
app.get('/api/admin', authMiddleware, requireRoles('admin', 'moderator'), handler);

// Require all roles
app.get('/api/super-admin', authMiddleware, requireAllRoles('admin', 'verified'), handler);

// Custom permission check
import { requirePermission } from '@developersailor/express-auth';

app.get('/api/custom', authMiddleware, requirePermission((user) => {
  return user.roles.includes('admin') || user.email.endsWith('@company.com');
}), handler);

Permission-based Middleware

import { requirePermissions, requireAllPermissions } from '@developersailor/express-auth';

// Require any of the permissions (herhangi biri yeterli)
app.get('/api/orders', 
  authMiddleware, 
  requirePermissions('order.read', 'order.admin'), 
  handler
);

// Require all permissions (hepsi gerekli)
app.get('/api/admin/orders', 
  authMiddleware, 
  requireAllPermissions('order.read', 'order.delete'), 
  handler
);

// Wildcard permissions
app.get('/api/users', 
  authMiddleware, 
  requirePermissions('user.*'), // matches user.read, user.write, etc.
  handler
);

// Combined role and permission check
import { requireRolesOrPermissions } from '@developersailor/express-auth';

app.delete('/api/users/:id', 
  authMiddleware, 
  requireRolesOrPermissions(['admin'], ['user.delete']), 
  handler
);

Advanced Authorization Configuration

const authRouter = createAuthRouter({
  jwtSecret: process.env.JWT_SECRET!,
  refreshTokenSecret: process.env.REFRESH_TOKEN_SECRET!,
  repositories: { userRepository, refreshTokenRepository },
  
  // Authorization yapılandırması
  authorization: {
    // Rolleri nasıl okuyacağız?
    getRoles: (user) => user.roles || [],
    
    // Permission'ları nasıl okuyacağız?
    getPermissions: (user) => user.permissions || [],
    
    // Her request'te DB'den güncel kullanıcı çek?
    // true: Güvenli ama yavaş (cache ile iyileştirilir)
    // false: JWT payload'dan okur (hızlı ama güncel olmayabilir)
    loadUserOnRequest: true,
    
    // Cache süresi (saniye)
    userCacheTTL: 60,
    
    // Ownership kontrolünde bypass edilecek roller
    ownershipBypassRoles: ['admin', 'superuser'],
  },
});

Ownership Control

import { requireOwnership } from '@developersailor/express-auth';

// Kullanıcı sadece kendi kaynaklarına erişebilir
// Admin ve superuser rolleri bypass eder (config'den ayarlanabilir)
app.get('/api/users/:userId/orders', 
  authMiddleware, 
  requireOwnership((req) => req.params.userId),
  handler
);

// Özel bypass rolleri ile
app.get('/api/users/:userId/private', 
  authMiddleware, 
  requireOwnership(
    (req) => req.params.userId,
    ['admin', 'support'] // Bu roller bypass eder
  ),
  handler
);

Decorators

import { Protected, Public, Roles, Permissions } from '@developersailor/express-auth';

class UserController {
  @Protected()
  @Roles('admin')
  async getAllUsers() {
    // Only admins can access
  }
  
  @Protected()
  @Permissions('user.read', 'user.write')
  async manageUsers() {
    // Requires user.read OR user.write permission
  }
  
  @Protected()
  @Roles('admin')
  @Permissions('order.refund')
  async refundOrder() {
    // Requires admin role AND order.refund permission
  }
  
  @Public()
  async getPublicInfo() {
    // Anyone can access
  }
}

Permission Formats

The package supports two permission formats:

Flat Format (Default):

// JWT Payload
{
  "permissions": ["user.read", "user.write", "order.*"]
}

// Wildcard support
requirePermissions('user.*')  // Matches user.read, user.write, etc.

Hierarchical Format:

// JWT Payload
{
  "permissions": {
    "user": { "read": true, "write": true },
    "order": { "read": true, "refund": true }
  }
}

// Enable in config
authorization: {
  hierarchicalPermissions: true
}

Testing

Use the built-in memory adapters for testing:

import { createMemoryRepositories } from '@developersailor/express-auth';

const { userRepository, refreshTokenRepository } = createMemoryRepositories();

const authRouter = createAuthRouter({
  jwtSecret: 'test-secret-min-32-chars-long!!!',
  refreshTokenSecret: 'another-test-secret-min-32-chars!!!',
  repositories: { userRepository, refreshTokenRepository },
});

Database Support

This package is database-agnostic and works with any database through the repository pattern. We provide ready-to-use examples for popular databases:

| Database | ORM | Example Location | |----------|-----|-----------------| | MongoDB | Mongoose | examples/express-mongodb/ | | MySQL | TypeORM | examples/express-mysql/ | | PostgreSQL | Prisma | examples/express-prisma/ | | MSSQL | Sequelize | examples/express-mssql/ | | SQLite | Prisma | examples/express-prisma/ | | In-Memory | Built-in | Package built-in |

Quick Start with Different Databases

MongoDB

cd examples/express-mongodb
npm install
# Start MongoDB, then:
npm run dev

MySQL

cd examples/express-mysql
npm install
# Setup MySQL database, then:
npm run db:sync
npm run dev

MSSQL

cd examples/express-mssql
npm install
# Setup SQL Server, then:
npm run db:sync
npm run dev

Prisma (PostgreSQL, MySQL, SQLite, SQL Server)

cd examples/express-prisma
npm install
npx prisma migrate dev
npm run dev

Read the Database Adapter Guide for detailed instructions on creating custom adapters.

Examples

Express + Prisma + OpenAPI

See the express-prisma example for a complete implementation with:

  • Prisma ORM integration
  • OpenAPI/Swagger documentation
  • TypeScript decorators
  • SQLite database
  • JWT authentication
cd examples/express-prisma
npm install
npx prisma migrate dev
npm run dev

OpenAPI Integration

The example includes OpenAPI decorator support:

# Swagger UI available at
http://localhost:3000/api-docs

Environment Variables

# Required
JWT_SECRET="your-super-secret-jwt-key-at-least-32-chars-long"
REFRESH_TOKEN_SECRET="your-different-super-secret-refresh-token-key"

# Database connection (your implementation)
DATABASE_URL="your-database-url"

# Optional
NODE_ENV=production
PORT=3000

Generating Secrets

# Generate secure random strings
node -e "console.log(require('crypto').randomBytes(64).toString('hex'))"

Security Checklist

Before going to production:

  • [x] Use strong JWT secrets (min 32 chars, random)
  • [x] Enable HTTPS (secure cookies)
  • [x] Set up rate limiting
  • [x] Configure CORS properly
  • [x] Use environment variables for secrets
  • [x] Enable password validation rules
  • [x] Review token expiration times
  • [x] Set up refresh token cleanup
  • [x] Monitor for suspicious activity

Type Exports

import {
  // Types
  AuthUser,
  AuthConfig,
  UserRepository,
  RefreshTokenRepository,
  RefreshTokenRecord,
  JWTPayload,
  TokenPair,
  LoginResult,
  AuthenticatedRequest,
  RefreshResult,
  // Services
  JWTService,
  PasswordService,
  // Middleware
  createAuthMiddleware,
  createOptionalAuthMiddleware,
  requireRoles,
  requireAllRoles,
  requirePermission,
  requireOwnership,
  getUser,
  isAuthenticated,
  // Decorators
  Protected,
  Public,
  Roles,
  PublicRoute,
  // Routes
  createAuthRouter,
  // Adapters
  createMemoryRepositories,
  MemoryUserRepository,
  MemoryRefreshTokenRepository,
} from '@developersailor/express-auth';

License

MIT © DeveloperSailor

Contributing

Contributions are welcome! Please read the contributing guide first.

Support