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

secure-node-auth

v1.4.3

Published

Blazing fast, zero-config authentication system with JWT for MySQL and PostgreSQL. Set up secure auth in seconds with auto-schema setup and extensible custom fields.

Readme

🔐 Secure Node Auth

Blazing fast, zero-config authentication system with JWT for MySQL & PostgreSQL. Set up secure auth in seconds!

npm version License: MIT Node.js Version

✨ Features

  • Zero Configuration - Works out of the box with sensible defaults
  • 🗄️ MySQL & PostgreSQL Support - Choose your preferred database with one line of config
  • 🔒 Production-Ready Security - Bcrypt hashing, JWT tokens, rate limiting, account lockout
  • 📧 Email Verification - URL-based or 6-digit code verification (new!)
  • 🔍 Audit Logging - Optional security event logging (customizable)
  • 🚀 Lightning Fast - Built with connection pooling and optimized queries
  • 🎨 Highly Customizable - Add custom fields, hooks, and configurations
  • 🔄 Auto Schema Setup - Automatically creates tables, indexes, and relationships
  • 🎯 Express & Fastify Support - Pre-built routes and middleware for both frameworks
  • 📦 Refresh Tokens - Secure token rotation with blacklisting
  • 🛡️ Attack Protection - Rate limiting, SQL injection protection, brute force prevention
  • 🔌 Extensible - Plugin system with before/after hooks
  • 📝 TypeScript Support - Full type definitions included

📦 Installation

npm install secure-node-auth

Dependencies:

  • mysql2 or pg - Database client (MySQL or PostgreSQL)
  • jsonwebtoken - JWT token generation
  • bcrypt - Password hashing
  • validator - Input validation
  • express or fastify - Web framework (peer dependencies)

For MySQL:

npm install secure-node-auth mysql2

For PostgreSQL:

npm install secure-node-auth pg

🚀 Quick Start

MySQL Setup (3 lines!)

const SecureNodeAuth = require('secure-node-auth');

const auth = new SecureNodeAuth({
  connection: {
    type: 'mysql', // Optional, defaults to MySQL
    host: 'localhost',
    user: 'root',
    password: 'your_password',
    database: 'myapp',
  },
});

await auth.init(); // Auto-creates tables!

// Use with Express
app.use('/auth', auth.router());

PostgreSQL Setup (3 lines!)

const SecureNodeAuth = require('secure-node-auth');

const auth = new SecureNodeAuth({
  connection: {
    type: 'postgres', // Use PostgreSQL
    host: 'localhost',
    user: 'postgres',
    password: 'your_password',
    database: 'myapp',
  },
});

await auth.init(); // Auto-creates tables!

// Use with Express
app.use('/auth', auth.router());

📘 Complete PostgreSQL Guide - Migration, Docker setup, and advanced features.

That's it! You now have a complete authentication system with:

  • ✅ User registration
  • ✅ Login with JWT
  • ✅ Token refresh
  • ✅ Password change
  • ✅ Profile management
  • ✅ Logout (single/all devices)

📖 Usage Examples

Complete Express Server

require('dotenv').config();
const express = require('express');
const SecureNodeAuth = require('secure-node-auth');

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

// Initialize auth system
const auth = new SecureNodeAuth({
  connection: {
    host: process.env.DB_HOST,
    user: process.env.DB_USER,
    password: process.env.DB_PASSWORD,
    database: process.env.DB_NAME,
  },
});

await auth.init();

// Mount auth routes
app.use('/auth', auth.router());

// Protected route example
app.get('/api/profile', auth.middleware(), async (req, res) => {
  const user = await auth.getUserById(req.user.userId);
  res.json({ user });
});

app.listen(3000, () => console.log('Server running on port 3000'));

Complete Fastify Server

const fastify = require('fastify')({ logger: true });
const SecureNodeAuth = require('secure-node-auth');
const secureNodeAuthPlugin = require('secure-node-auth/src/middleware/FastifyPlugin');

async function start() {
  // Initialize auth system
  const auth = new SecureNodeAuth({
    connection: {
      host: process.env.DB_HOST,
      user: process.env.DB_USER,
      password: process.env.DB_PASSWORD,
      database: process.env.DB_NAME,
    },
  });

  await auth.init();

  // Register auth plugin (includes all routes + middleware)
  await fastify.register(secureNodeAuthPlugin, {
    authInstance: auth,
    routeOptions: {
      prefix: '/auth',
    },
  });

  // Protected route example
  fastify.get(
    '/api/profile',
    {
      preHandler: fastify.authenticate,
    },
    async (request, reply) => {
      const user = await auth.getUserById(request.user.userId);
      return { user };
    }
  );

  await fastify.listen({ port: 3000 });
  console.log('🚀 Server running on http://localhost:3000');
}

start();

📘 Complete Fastify Guide - Detailed Fastify integration, rate limiting, validation, and performance tips.

Adding Custom Fields

✅ Recommended: Add fields before initialization

const auth = new SecureNodeAuth({
  /* config */
});

// Add custom fields BEFORE init()
auth.addField({
  name: 'phoneNumber',
  type: 'VARCHAR(20)',
  required: false,
  unique: true,
});

auth.addField({
  name: 'companyName',
  type: 'VARCHAR(255)',
  required: false,
});

auth.addField({
  name: 'subscriptionTier',
  type: "ENUM('free', 'premium', 'enterprise')",
  defaultValue: 'free',
});

await auth.init();

// Now register with custom fields
await auth.register({
  email: '[email protected]',
  password: 'SecurePass123!',
  phoneNumber: '+1234567890',
  companyName: 'Tech Corp',
  subscriptionTier: 'premium',
});

⚠️ Advanced: Runtime schema changes (use with caution)

For existing databases, you can add columns after initialization using dangerous methods:

// Already initialized
await auth.init();

// Add single column (⚠️ can cause table locks)
await auth.dangerouslyAddColumn(
  {
    name: 'phoneNumber',
    type: 'VARCHAR(20)',
    unique: true,
  },
  { confirmed: true }
);

// Add multiple columns with transaction (PostgreSQL)
await auth.dangerouslyMigrateSchema(
  [
    { name: 'age', type: 'INTEGER', defaultValue: 0 },
    { name: 'city', type: 'VARCHAR(100)' },
  ],
  { confirmed: true, useTransaction: true }
);

📖 Complete Migration Guide - Safety tips, examples, and best practices.

Using Hooks

// Before/after registration
auth.on('beforeRegister', async (userData) => {
  console.log('New user signing up:', userData.email);
  // Add custom validation, check blacklist, etc.
});

auth.on('afterRegister', async (result) => {
  console.log('User registered:', result.user.email);
  // Send welcome email, create user profile, etc.
  await sendWelcomeEmail(result.user.email);
});

// Before/after login
auth.on('beforeLogin', async ({ email }) => {
  console.log('Login attempt:', email);
});

auth.on('afterLogin', async (result) => {
  console.log('Successful login:', result.user.email);
  // Track analytics, update last login, etc.
});

Manual Authentication Flow

// Register
const { user, tokens } = await auth.register({
  email: '[email protected]',
  password: 'SecurePass123!',
  firstName: 'John',
  lastName: 'Doe',
});

// Login
const login = await auth.login('[email protected]', 'SecurePass123!');
console.log(login.tokens.accessToken);
console.log(login.tokens.refreshToken);

// Verify token
const decoded = await auth.verifyAccessToken(login.tokens.accessToken);
console.log(decoded.userId, decoded.email);

// Refresh access token
const { accessToken } = await auth.refreshToken(login.tokens.refreshToken);

// Change password
await auth.changePassword(userId, 'OldPass123!', 'NewPass456!');

// Logout
await auth.logout(refreshToken);

// Logout all devices
await auth.logoutAll(userId);

🔧 Configuration Options

const auth = new SecureNodeAuth({
  // Database connection
  connection: {
    host: 'localhost',
    user: 'root',
    password: '',
    database: 'myapp',
    port: 3306,
    connectionLimit: 10,
  },

  // JWT configuration
  jwt: {
    accessSecret: 'your-access-secret',
    refreshSecret: 'your-refresh-secret',
    accessExpiresIn: '15m', // 15 minutes
    refreshExpiresIn: '7d', // 7 days
  },

  // Security settings
  security: {
    bcryptRounds: 10, // Higher = more secure, slower
    maxLoginAttempts: 5, // Account lockout threshold
    lockoutTime: 900000, // 15 minutes in milliseconds
    passwordMinLength: 8,
    passwordRequireUppercase: true,
    passwordRequireNumbers: true,
    passwordRequireSpecialChars: true,
  },

  // Custom table names
  tables: {
    users: 'my_users',
    refreshTokens: 'my_tokens',
    loginAttempts: 'my_login_attempts',
  },
});

📡 API Endpoints

When you mount auth.router(), these endpoints are automatically available:

| Method | Endpoint | Description | Auth Required | | ------ | ------------------ | --------------------- | ------------- | | POST | /register | Register new user | ❌ | | POST | /login | Login user | ❌ | | POST | /refresh | Refresh access token | ❌ | | POST | /logout | Logout (revoke token) | ❌ | | POST | /logout-all | Logout all devices | ✅ | | GET | /me | Get current user | ✅ | | PATCH | /me | Update user profile | ✅ | | POST | /change-password | Change password | ✅ | | POST | /verify | Verify token | ❌ | | GET | /health | Health check | ❌ |

Request/Response Examples

Register:

POST /auth/register
{
  "email": "[email protected]",
  "password": "SecurePass123!",
  "firstName": "John",
  "lastName": "Doe"
}

// Response
{
  "success": true,
  "message": "User registered successfully",
  "data": {
    "user": { ... },
    "tokens": {
      "accessToken": "eyJhbG...",
      "refreshToken": "eyJhbG...",
      "expiresIn": "15m"
    }
  }
}

Login:

POST /auth/login
{
  "email": "[email protected]",
  "password": "SecurePass123!"
}

// Response
{
  "success": true,
  "message": "Login successful",
  "data": {
    "user": { ... },
    "tokens": { ... }
  }
}

📋 Complete API Methods

Core Authentication

  • await auth.init() - Initialize system and create tables
  • await auth.register(userData) - Register new user
  • await auth.login(email, password) - Login and get tokens
  • await auth.refreshToken(refreshToken) - Get new access token
  • await auth.logout(refreshToken) - Logout single session
  • await auth.logoutAll(userId) - Logout all sessions
  • await auth.verifyAccessToken(token) - Verify JWT token

User Management

  • await auth.getUserById(userId) - Get user by ID
  • await auth.getUserByEmail(email) - Get user by email
  • await auth.updateUser(userId, updates) - Update user data
  • await auth.updateProfile(userId, updates) - Update profile (alias)
  • await auth.changePassword(userId, oldPass, newPass) - Change password
  • await auth.getUserCount() - Get total user count
  • await auth.isAccountLocked(email) - Check if account locked

Email Verification

URL-Based Verification:

  • await auth.sendVerificationEmail(email, url) - Send verification email
  • await auth.verifyEmail(token) - Verify email with token
  • await auth.resendVerificationEmail(email, url) - Resend verification

6-Digit Code Verification (New!):

  • await auth.sendVerificationCode(email, options) - Send 6-digit code
  • await auth.verifyCode(email, code) - Verify with 6-digit code

Utility:

  • await auth.isEmailVerified(userId) - Check if email verified

💡 Tip: Use URL verification for web apps, 6-digit codes for mobile apps or better UX. See Verification Guide

Password Reset

URL-Based Reset:

  • await auth.sendPasswordResetEmail(email, url) - Send reset email
  • await auth.resetPassword(token, newPassword) - Reset password

6-Digit Code Reset (New!):

  • await auth.sendPasswordResetCode(email, options) - Send 6-digit reset code
  • await auth.resetPasswordWithCode(email, code, newPassword) - Reset with code

💡 Tip: Use URL reset for web apps, 6-digit codes for mobile apps. Codes expire in 15 minutes (customizable).

Database Maintenance

  • await auth.cleanupExpiredTokens() - Clean expired tokens
  • await auth.cleanupExpiredLoginAttempts(days) - Clean old attempts
  • await auth.cleanupRevokedRefreshTokens(days) - Clean revoked tokens
  • await auth.performMaintenance(options) - Run all cleanup
  • auth.getPool() - Get raw database pool

Schema Customization

  • auth.addField(config) - Add field before init
  • await auth.dangerouslyAddColumn(config, options) - Add column at runtime
  • await auth.dangerouslyMigrateSchema(fields, options) - Batch migration

Hooks & Integration

  • auth.on(event, callback) - Register lifecycle hooks
  • auth.router(options) - Get Express/Fastify router
  • auth.middleware() - Get auth middleware
  • await auth.close() - Close database connection

📖 Complete API Reference - Detailed documentation with examples

🛡️ Security Features

Password Security

  • ✅ Bcrypt hashing (configurable rounds)
  • ✅ Minimum length requirements
  • ✅ Complexity requirements (uppercase, numbers, special chars)
  • ✅ Common password blacklist

Account Protection

  • ✅ Brute force protection (rate limiting)
  • ✅ Account lockout after failed attempts
  • ✅ Automatic lockout expiration
  • ✅ Login attempt tracking

Token Security

  • ✅ Separate access and refresh tokens
  • ✅ Short-lived access tokens (15m default)
  • ✅ Token revocation support
  • ✅ Logout from all devices
  • ✅ Automatic token cleanup

Database Security

  • ✅ Parameterized queries (SQL injection protection)
  • ✅ Connection pooling
  • ✅ Indexed queries for performance
  • ✅ Foreign key constraints

🏗️ Database Schema

The package automatically creates these tables:

secure_auth_users

- id (PRIMARY KEY)
- email (UNIQUE, INDEXED)
- password (HASHED)
- firstName
- lastName
- emailVerified
- isActive
- createdAt
- updatedAt
+ your custom fields

secure_auth_refresh_tokens

- id (PRIMARY KEY)
- userId (FOREIGN KEY)
- token
- revoked
- expiresAt (INDEXED)
- createdAt

secure_auth_login_attempts

- id (PRIMARY KEY)
- email (INDEXED)
- success
- ipAddress
- userAgent
- attemptedAt

🎣 Hooks System

Available hooks:

  • beforeRegister - Before user registration
  • afterRegister - After successful registration
  • beforeLogin - Before login attempt
  • afterLogin - After successful login
  • beforeTokenRefresh - Before token refresh
  • afterTokenRefresh - After token refresh
auth.on('afterRegister', async (result) => {
  // Your custom logic
  await sendWelcomeEmail(result.user.email);
  await createUserProfile(result.user.id);
});

🔌 Middleware Usage

// Protect single route
app.get('/api/protected', auth.middleware(), (req, res) => {
  console.log(req.user); // { userId, email, iat, exp }
  res.json({ message: 'Protected data' });
});

// Protect multiple routes
app.use('/api', auth.middleware());

// Custom role-based middleware
const requireAdmin = async (req, res, next) => {
  const user = await auth.getUserById(req.user.userId);
  if (user.role !== 'admin') {
    return res.status(403).json({ error: 'Admin access required' });
  }
  next();
};

app.get('/api/admin', auth.middleware(), requireAdmin, (req, res) => {
  res.json({ message: 'Admin only' });
});

🧪 Testing

# Install dependencies
npm install

# Run example server
npm run example

# The server will start on http://localhost:3000

Test endpoints with curl:

# Register
curl -X POST http://localhost:3000/auth/register \
  -H "Content-Type: application/json" \
  -d '{"email":"[email protected]","password":"SecurePass123!"}'

# Login
curl -X POST http://localhost:3000/auth/login \
  -H "Content-Type: application/json" \
  -d '{"email":"[email protected]","password":"SecurePass123!"}'

📚 Advanced Topics

Environment Variables

Create a .env file:

DB_HOST=localhost
DB_USER=root
DB_PASSWORD=your_password
DB_NAME=myapp
DB_PORT=3306

JWT_ACCESS_SECRET=your_super_secret_access_key
JWT_REFRESH_SECRET=your_super_secret_refresh_key
JWT_ACCESS_EXPIRES_IN=15m
JWT_REFRESH_EXPIRES_IN=7d

BCRYPT_ROUNDS=10
MAX_LOGIN_ATTEMPTS=5
LOCKOUT_TIME=900000

PORT=3000

Token Cleanup

// Clean up expired tokens (run periodically)
await auth.db.cleanupExpiredTokens(auth.options.tables.refreshTokens);

// With cron job
const cron = require('node-cron');
cron.schedule('0 0 * * *', async () => {
  await auth.db.cleanupExpiredTokens(auth.options.tables.refreshTokens);
  console.log('Cleaned up expired tokens');
});

Direct Database Access

// Get raw database pool for custom queries
const pool = auth.getPool();

const [rows] = await pool.execute(
  'SELECT COUNT(*) as total FROM secure_auth_users WHERE isActive = ?',
  [true]
);

console.log('Active users:', rows[0].total);

🔧 Troubleshooting

Connection Timeout (ETIMEDOUT)

If you're getting ETIMEDOUT errors:

const auth = new SecureNodeAuth({
  connection: {
    host: 'localhost',
    user: 'root',
    password: 'password',
    database: 'myapp',
    // Add these timeout settings
    connectTimeout: 20000,      // 20 seconds (default: 10s)
    acquireTimeout: 20000,      // 20 seconds (default: 10s)
    timeout: 20000,             // 20 seconds (default: 10s)
    retryAttempts: 5,           // Retry 5 times (default: 3)
    retryDelay: 2000            // Wait 2s between retries (default: 1s)
  }
});

Common causes:

  • ✅ MySQL server not running → sudo service mysql start
  • ✅ Wrong host/port → Verify connection details
  • ✅ Firewall blocking connection → Check firewall rules
  • ✅ MySQL not accepting remote connections → Edit my.cnf (bind-address)

Connection Refused (ECONNREFUSED)

# Check if MySQL is running
sudo service mysql status

# Start MySQL
sudo service mysql start

# Check MySQL port
netstat -an | grep 3306

Access Denied (ER_ACCESS_DENIED_ERROR)

-- Grant permissions to user
GRANT ALL PRIVILEGES ON myapp.* TO 'myuser'@'localhost';
FLUSH PRIVILEGES;

Slow Initialization

Enable connection pooling (already enabled by default):

const auth = new SecureNodeAuth({
  connection: {
    connectionLimit: 20,        // Max connections (default: 10)
    queueLimit: 0,              // No queue limit (default: 0)
    enableKeepAlive: true,      // Keep connections alive (default: true)
    keepAliveInitialDelay: 0    // Initial delay (default: 0)
  }
});

📚 Additional Guides

🔐 Security Features

This package has undergone 5 rounds of comprehensive security audits and implements industry best practices:

  • SQL Injection Protection: Parameterized queries + escaped identifiers
  • Token Hashing: SHA-256 hashing of refresh tokens in database
  • Email Normalization: Prevents duplicate accounts via case variations
  • Audit Logging: Configurable logging for all security events
  • Brute Force Protection: Account lockout after failed attempts
  • Password Security: Bcrypt with configurable rounds (4-31)
  • Input Validation: Multi-layer validation and sanitization
  • Secure Configuration: Validated defaults with safe fallbacks

Security Standards Compliance: OWASP Top 10, NIST Framework, PCI-DSS, GDPR

See SECURITY.md for complete security documentation.

🤝 Contributing

Contributions are welcome! Please feel free to submit a Pull Request.

📄 License

MIT © 2025

🔗 Links

💡 Support

If you find this package helpful, please consider:

  • ⭐ Starring the repository
  • 🐛 Reporting bugs
  • 💡 Suggesting new features
  • 📖 Improving documentation

Built with ❤️ for the Node.js community