JSPM

  • ESM via JSPM
  • ES Module Entrypoint
  • Export Map
  • Keywords
  • License
  • Repository URL
  • TypeScript Types
  • README
  • Created
  • Published
  • Downloads 2
  • Score
    100M100P100Q84367F
  • License MIT

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.

Package Exports

  • secure-node-auth
  • secure-node-auth/src/index.js
  • secure-node-auth/src/middleware/FastifyPlugin
  • secure-node-auth/src/middleware/FastifyPlugin.js

This package does not declare an exports field, so the exports above have been automatically detected and optimized by JSPM instead. If any package subpath is missing, it is recommended to post an issue to the original package (secure-node-auth) to support the "exports" field. If that is not possible, create a JSPM override to customize the exports field for this package.

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: 'user@example.com',
  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: 'john@example.com',
  password: 'SecurePass123!',
  firstName: 'John',
  lastName: 'Doe',
});

// Login
const login = await auth.login('john@example.com', '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": "user@example.com",
  "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": "user@example.com",
  "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":"test@example.com","password":"SecurePass123!"}'

# Login
curl -X POST http://localhost:3000/auth/login \
  -H "Content-Type: application/json" \
  -d '{"email":"test@example.com","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

๐Ÿ’ก 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