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

@unkown812/gatekeeper-auth

v1.0.1

Published

A secure, developer-friendly authentication middleware for Node.js and TypeScript.

Readme

🔐 Gatekeeper Auth

Production-ready authentication system for Node.js applications

A flexible, secure authentication solution that works both as a standalone microservice and as an npm package for Express.js applications. Built with TypeScript, MongoDB, and JWT.

npm version License: ISC


Why Gatekeeper Auth?

  • Quick Integration – Add authentication to your app in minutes
  • 🔒 Enterprise Security – Bcrypt hashing, JWT tokens, email verification
  • 🎯 Flexible Architecture – Use as a package or standalone service
  • 📧 Email Ready – Built-in verification and password reset emails
  • 🛡️ Role-Based Access – Easy authorization with user roles
  • 📘 TypeScript Native – Full type safety and IntelliSense support

Table of Contents


Installation

npm install gatekeeper-auth

Requirements:

  • Node.js 14+
  • MongoDB 4.0+
  • Express.js 4.x

Quick Start

Option 1: Integrate into Your App

Add authentication to your existing Express.js application:

import express from 'express';
import { initGatekeeper, authRouter, protect, authorize } from 'gatekeeper-auth';

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

// Initialize authentication system
await initGatekeeper({
  mongoUri: 'mongodb://localhost:27017/myapp',
  jwtSecret: process.env.JWT_SECRET,
  jwtExpiresIn: '15m',
  jwtRefreshExpiresIn: '7d',
  bcryptSaltRounds: 12,
  emailService: {
    host: 'smtp.gmail.com',
    port: 587,
    secure: false,
    auth: {
      user: process.env.EMAIL_USER,
      pass: process.env.EMAIL_PASS,
    },
    from: '[email protected]',
  },
  verificationTokenExpiry: 86400000, // 24 hours
  resetTokenExpiry: 3600000, // 1 hour
  baseUrl: 'http://localhost:3000',
});

// Mount authentication routes
app.use('/api/auth', authRouter);

// Protect your routes
app.get('/api/profile', protect, (req, res) => {
  res.json({ user: req.user });
});

// Add role-based access control
app.delete('/api/admin/users/:id', 
  protect, 
  authorize(['admin']), 
  (req, res) => {
    res.json({ message: 'User deleted' });
  }
);

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

Option 2: Run as Standalone Service

Use Gatekeeper Auth as a dedicated authentication microservice:

  1. Install and configure:

    npm install gatekeeper-auth
  2. Create .env file:

    MONGO_URI=mongodb://localhost:27017/auth
    JWT_SECRET=your-secret-key
    EMAIL_HOST=smtp.gmail.com
    [email protected]
    EMAIL_PASS=your-password
    PORT=3000
  3. Start the server:

    npm run dev

The authentication service will be available at http://localhost:3000.


Configuration

Environment Variables

Create a .env file in your project root:

# Database
MONGO_URI=mongodb://localhost:27017/gatekeeper-auth

# JWT
JWT_SECRET=your-super-secret-jwt-key-change-in-production
JWT_EXPIRES_IN=15m
JWT_REFRESH_EXPIRES_IN=7d

# Security
BCRYPT_SALT_ROUNDS=12

# Email (SMTP)
EMAIL_HOST=smtp.gmail.com
EMAIL_PORT=587
EMAIL_SECURE=false
[email protected]
EMAIL_PASS=your-app-specific-password
[email protected]

# Tokens
VERIFICATION_TOKEN_EXPIRY=86400000  # 24 hours in ms
RESET_TOKEN_EXPIRY=3600000          # 1 hour in ms

# Application
PORT=3000
NODE_ENV=development
BASE_URL=http://localhost:3000

Configuration Object

interface GatekeeperConfig {
  mongoUri: string;
  jwtSecret: string;
  jwtExpiresIn: string;              // e.g., '15m', '1h', '7d'
  jwtRefreshExpiresIn: string;
  bcryptSaltRounds: number;
  emailService: {
    host: string;
    port: number;
    secure: boolean;
    auth: {
      user: string;
      pass: string;
    };
    from: string;
  };
  verificationTokenExpiry: number;   // milliseconds
  resetTokenExpiry: number;          // milliseconds
  baseUrl?: string;
  rateLimiting?: {
    enabled: boolean;
    windowMs: number;
    maxRequests: number;
  };
}

API Reference

All endpoints return JSON responses with consistent structure:

{
  "status": "success" | "error",
  "message": string,
  "data": object  // when applicable
}

Endpoints

POST /auth/register

Register a new user account.

Request:

{
  "username": "johndoe",
  "email": "[email protected]",
  "password": "SecurePass123!"
}

Response:

{
  "status": "success",
  "message": "Registration successful. Please check your email to verify your account."
}

Validation:

  • Username: 3-30 characters, alphanumeric and underscores
  • Email: Valid email format
  • Password: 8-100 characters, must include uppercase, lowercase, number, and special character

POST /auth/verify-email

Verify email address using token sent to user's email.

Request:

{
  "token": "verification-token-from-email"
}

Response:

{
  "status": "success",
  "message": "Email verified successfully. You can now log in."
}

POST /auth/login

Authenticate user and receive access tokens.

Request:

{
  "email": "[email protected]",
  "password": "SecurePass123!"
}

Response:

{
  "status": "success",
  "data": {
    "user": {
      "id": "507f1f77bcf86cd799439011",
      "username": "johndoe",
      "email": "[email protected]",
      "role": "user",
      "isVerified": true
    },
    "tokens": {
      "accessToken": "eyJhbGciOiJIUzI1NiIs...",
      "refreshToken": "eyJhbGciOiJIUzI1NiIs..."
    }
  }
}

Notes:

  • Users must verify their email before logging in
  • Access tokens expire in 15 minutes (default)
  • Refresh tokens expire in 7 days (default)

POST /auth/forgot-password

Request a password reset link.

Request:

{
  "email": "[email protected]"
}

Response:

{
  "status": "success",
  "message": "If an account exists with this email, you will receive a password reset link."
}

Notes:

  • Always returns success to prevent email enumeration
  • Reset token valid for 1 hour (default)

POST /auth/reset-password

Reset password using token from email.

Request:

{
  "token": "reset-token-from-email",
  "password": "NewSecurePass123!"
}

Response:

{
  "status": "success",
  "message": "Password reset successfully. You can now log in with your new password."
}

POST /auth/refresh-token

Obtain a new access token using refresh token.

Request:

{
  "refreshToken": "eyJhbGciOiJIUzI1NiIs..."
}

Response:

{
  "status": "success",
  "data": {
    "accessToken": "eyJhbGciOiJIUzI1NiIs...",
    "refreshToken": "eyJhbGciOiJIUzI1NiIs..."
  }
}

Middleware

protect

Validates JWT access token and attaches user data to request object.

Usage:

import { protect } from 'gatekeeper-auth';

app.get('/api/profile', protect, (req, res) => {
  // req.user is now available
  res.json({
    userId: req.user.userId,
    email: req.user.email,
    role: req.user.role
  });
});

Request Headers:

Authorization: Bearer <access-token>

Error Responses:

  • 401 Unauthorized – Token missing or invalid
  • 403 Forbidden – Token expired

authorize

Restricts access based on user roles.

Usage:

import { protect, authorize } from 'gatekeeper-auth';

// Single role
app.delete('/api/users/:id', 
  protect, 
  authorize(['admin']), 
  (req, res) => {
    res.json({ message: 'User deleted' });
  }
);

// Multiple roles
app.put('/api/posts/:id', 
  protect, 
  authorize(['admin', 'moderator']), 
  (req, res) => {
    res.json({ message: 'Post updated' });
  }
);

Available Roles:

  • user – Default role for registered users
  • moderator – Elevated permissions
  • admin – Full access

Error Response:

  • 403 Forbidden – User lacks required role

Security

Password Requirements

All passwords must meet these criteria:

  • ✅ Minimum 8 characters
  • ✅ Maximum 100 characters
  • ✅ At least one uppercase letter (A-Z)
  • ✅ At least one lowercase letter (a-z)
  • ✅ At least one number (0-9)
  • ✅ At least one special character (!@#$%^&*, etc.)

Security Features

| Feature | Implementation | |---------|---------------| | Password Hashing | Bcrypt with configurable salt rounds (default: 12) | | Token Security | SHA-256 hashing for reset/verification tokens | | JWT Authentication | RS256 or HS256 signing algorithms | | Email Verification | Required before login | | Token Expiration | Configurable for all token types | | Input Validation | Zod schemas on all endpoints | | Email Enumeration Prevention | Generic responses for forgot password | | Error Handling | Centralized middleware with sanitized messages |

Best Practices

  1. Use strong JWT secrets – Generate with openssl rand -base64 32
  2. Enable HTTPS – Always use SSL/TLS in production
  3. Rotate secrets – Change JWT secrets periodically
  4. Use app-specific passwords – For Gmail, use App Passwords, not your account password
  5. Monitor failed login attempts – Implement rate limiting
  6. Keep dependencies updated – Run npm audit regularly

Architecture

Project Structure

src/
├── config/
│   ├── db.ts                      # MongoDB connection
│   └── gatekeeper.config.ts       # Configuration loader
├── controllers/
│   └── auth.controller.ts         # Route handlers
├── middleware/
│   ├── auth.middleware.ts         # JWT verification
│   ├── role.middleware.ts         # Role checking
│   ├── validate.middleware.ts     # Input validation
│   └── error.middleware.ts        # Error handling
├── models/
│   └── user.model.ts              # User schema & methods
├── routes/
│   └── auth.routes.ts             # Route definitions
├── services/
│   ├── auth.service.ts            # Business logic
│   ├── token.service.ts           # Token generation/validation
│   └── email.service.ts           # Email sending
├── types/
│   └── index.ts                   # TypeScript interfaces
├── utils/
│   ├── hash.ts                    # Hashing utilities
│   └── validation.schemas.ts      # Zod schemas
├── index.ts                       # Package exports
└── server.ts                      # Standalone server

Data Flow

Request → Validation Middleware → Controller → Service → Database
                                                    ↓
Response ← Error Handler ← Controller ← Service ←──┘

Examples

Complete Integration Example

import express from 'express';
import { initGatekeeper, authRouter, protect, authorize } from 'gatekeeper-auth';

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

// Initialize
await initGatekeeper({
  mongoUri: process.env.MONGO_URI!,
  jwtSecret: process.env.JWT_SECRET!,
  jwtExpiresIn: '15m',
  jwtRefreshExpiresIn: '7d',
  bcryptSaltRounds: 12,
  emailService: {
    host: process.env.EMAIL_HOST!,
    port: parseInt(process.env.EMAIL_PORT!),
    secure: false,
    auth: {
      user: process.env.EMAIL_USER!,
      pass: process.env.EMAIL_PASS!,
    },
    from: process.env.EMAIL_FROM!,
  },
  verificationTokenExpiry: 86400000,
  resetTokenExpiry: 3600000,
  baseUrl: process.env.BASE_URL,
});

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

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

// Protected routes
app.get('/api/profile', protect, (req, res) => {
  res.json({ user: req.user });
});

// Role-based routes
app.get('/api/admin/dashboard', 
  protect, 
  authorize(['admin']), 
  (req, res) => {
    res.json({ message: 'Admin dashboard' });
  }
);

app.get('/api/moderator/reports', 
  protect, 
  authorize(['admin', 'moderator']), 
  (req, res) => {
    res.json({ message: 'Moderation reports' });
  }
);

// Error handling
app.use((err, req, res, next) => {
  console.error(err);
  res.status(err.status || 500).json({
    status: 'error',
    message: err.message || 'Internal server error'
  });
});

const PORT = process.env.PORT || 3000;
app.listen(PORT, () => {
  console.log(`Server running on port ${PORT}`);
});

Frontend Integration Example

// Register user
async function register(username, email, password) {
  const response = await fetch('http://localhost:3000/api/auth/register', {
    method: 'POST',
    headers: { 'Content-Type': 'application/json' },
    body: JSON.stringify({ username, email, password })
  });
  return response.json();
}

// Login
async function login(email, password) {
  const response = await fetch('http://localhost:3000/api/auth/login', {
    method: 'POST',
    headers: { 'Content-Type': 'application/json' },
    body: JSON.stringify({ email, password })
  });
  const data = await response.json();
  
  // Store tokens
  localStorage.setItem('accessToken', data.data.tokens.accessToken);
  localStorage.setItem('refreshToken', data.data.tokens.refreshToken);
  
  return data;
}

// Make authenticated request
async function getProfile() {
  const token = localStorage.getItem('accessToken');
  const response = await fetch('http://localhost:3000/api/profile', {
    headers: {
      'Authorization': `Bearer ${token}`
    }
  });
  
  // If token expired, refresh it
  if (response.status === 403) {
    await refreshAccessToken();
    return getProfile(); // Retry
  }
  
  return response.json();
}

// Refresh access token
async function refreshAccessToken() {
  const refreshToken = localStorage.getItem('refreshToken');
  const response = await fetch('http://localhost:3000/api/auth/refresh-token', {
    method: 'POST',
    headers: { 'Content-Type': 'application/json' },
    body: JSON.stringify({ refreshToken })
  });
  const data = await response.json();
  
  localStorage.setItem('accessToken', data.data.accessToken);
  localStorage.setItem('refreshToken', data.data.refreshToken);
}

Development

Build

npm run build

Compiles TypeScript to JavaScript in the dist/ directory.

Testing

npm test

Development Mode

npm run dev

Runs the standalone server with hot reload.


Troubleshooting

Common Issues

Issue: "Email not sending"

  • Check SMTP credentials in .env
  • For Gmail, use App Passwords instead of your account password
  • Verify firewall isn't blocking port 587

Issue: "JWT token invalid"

  • Ensure JWT_SECRET matches between requests
  • Check token hasn't expired
  • Verify Authorization header format: Bearer <token>

Issue: "Database connection failed"

  • Confirm MongoDB is running
  • Check MONGO_URI in .env
  • Ensure database user has proper permissions

Issue: "TypeScript errors"

  • Run npm install to ensure all types are installed
  • Check tsconfig.json includes proper settings
  • Verify you're using Node.js 14+

Contributing

Contributions are welcome! Please follow these guidelines:

  1. Fork the repository
  2. Create a feature branch (git checkout -b feature/amazing-feature)
  3. Commit your changes (git commit -m 'Add amazing feature')
  4. Push to the branch (git push origin feature/amazing-feature)
  5. Open a Pull Request

License

ISC © jayjogane


Support


Acknowledgments

Built with:


⭐ If this package helped you, please consider giving it a star on GitHub!