@unkown812/gatekeeper-auth
v1.0.1
Published
A secure, developer-friendly authentication middleware for Node.js and TypeScript.
Maintainers
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.
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-authRequirements:
- 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:
Install and configure:
npm install gatekeeper-authCreate
.envfile:MONGO_URI=mongodb://localhost:27017/auth JWT_SECRET=your-secret-key EMAIL_HOST=smtp.gmail.com [email protected] EMAIL_PASS=your-password PORT=3000Start 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:3000Configuration 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 invalid403 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 usersmoderator– Elevated permissionsadmin– 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
- Use strong JWT secrets – Generate with
openssl rand -base64 32 - Enable HTTPS – Always use SSL/TLS in production
- Rotate secrets – Change JWT secrets periodically
- Use app-specific passwords – For Gmail, use App Passwords, not your account password
- Monitor failed login attempts – Implement rate limiting
- Keep dependencies updated – Run
npm auditregularly
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 serverData 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 buildCompiles TypeScript to JavaScript in the dist/ directory.
Testing
npm testDevelopment Mode
npm run devRuns 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_SECRETmatches between requests - Check token hasn't expired
- Verify Authorization header format:
Bearer <token>
Issue: "Database connection failed"
- Confirm MongoDB is running
- Check
MONGO_URIin.env - Ensure database user has proper permissions
Issue: "TypeScript errors"
- Run
npm installto ensure all types are installed - Check
tsconfig.jsonincludes proper settings - Verify you're using Node.js 14+
Contributing
Contributions are welcome! Please follow these guidelines:
- Fork the repository
- Create a feature branch (
git checkout -b feature/amazing-feature) - Commit your changes (
git commit -m 'Add amazing feature') - Push to the branch (
git push origin feature/amazing-feature) - Open a Pull Request
License
ISC © jayjogane
Support
- 📧 Email: [email protected]
- 🐛 Issues: GitHub Issues
- 📖 Documentation: Full Docs
Acknowledgments
Built with:
- Express.js - Web framework
- MongoDB - Database
- Mongoose - ODM
- JWT - Authentication tokens
- Bcrypt - Password hashing
- Zod - Schema validation
- Nodemailer - Email sending
⭐ If this package helped you, please consider giving it a star on GitHub!
