One-line security for Express.js
HiSecure unifies authentication, validation, sanitization, rate-limiting, headers and parsing
into a single, consistent security layer for Express applications.
Modern Express applications require multiple security libraries to handle authentication, password hashing, validation, sanitization, rate limiting, headers, compression and parsing. Managing these separately leads to duplicated logic, configuration drift and subtle bugs.
HiSecure solves this by acting as a single orchestration layer.
- Password hashing (Argon2 with bcrypt fallback)
- JWT authentication and route protection
- Google login (ID token verification)
- Request validation and sanitization
- Rate limiting and abuse prevention
- CORS, security headers and compression
- JSON, URL and query parsing
| Capability | Status | Notes |
|---|---|---|
| JWT Authentication | Stable | Issuer, audience, expiry and subject supported |
| Password Hashing | Stable | Argon2 primary with bcrypt fallback |
| Google Login | Stable | ID token verification adapter included |
| Route Protection (RBAC) | Stable | Role-based access via JWT payload |
| Validation | Stable | Zod and express-validator supported |
| Sanitization | Stable | HTML injection and XSS protection |
| Rate Limiting | Stable | Presets and per-route configuration |
| CORS & Headers | Stable | Helmet, HPP and CORS integrated |
| Compression | Stable | gzip via a single flag |
| Logging | Improved | Structured, lifecycle-aware logs with adapter, manager and fallback visibility. Designed for production debugging without leaking sensitive data. |
- Improved structured logging across core lifecycle
- Clear visibility into adapter initialization and fallbacks
- Layer-based logs (core, managers, adapters) for easier debugging
- No public API changes (safe patch release)
- Single global middleware for security
- No manual wiring of multiple packages
- Consistent error handling and lifecycle-aware logging
- Safe defaults with escape hatches
- Beginner-friendly, production-ready
npm install hi-secureimport express from "express";
import { HiSecure } from "hi-secure";
const app = express();
app.use(HiSecure.middleware("api"));
app.listen(3000);
const hash = await HiSecure.hash(password);
const isValid = await HiSecure.verify(password, hash);
router.post(
"/register",
HiSecure.validate([...]),
controller
);
HiSecure.rateLimit({ max: 5, windowMs: 15 * 60 * 1000 });
Global CORS defines the baseline access rules for your entire application. These rules apply to all routes unless explicitly overridden at the route level.
This is ideal for standard APIs where most endpoints share the same access policy.
Enable CORS globally using default configuration.
app.use(
HiSecure.middleware({
cors: true
})
);
Define explicit CORS rules for all routes.
app.use(
HiSecure.middleware({
cors: {
origin: ["https://app.example.com"],
methods: ["GET", "POST", "PUT", "DELETE"],
allowedHeaders: ["Content-Type", "Authorization"],
credentials: true
}
})
);
Allow multiple frontends (web, admin, mobile) to access the same API.
app.use(
HiSecure.middleware({
cors: {
origin: [
"https://web.example.com",
"https://admin.example.com",
"https://mobile.example.com"
],
credentials: true
}
})
);
Use open CORS rules for public or read-only APIs.
app.use(
HiSecure.middleware({
cors: {
origin: "*",
methods: ["GET"]
}
})
);
HiSecure supports fine-grained security control at the route level. Each capability can be configured independently without affecting global middleware.
This allows you to apply strict security where needed (auth, payments, admin) and relaxed rules for public or internal endpoints.
Route-level CORS is useful when different consumers access different endpoints (e.g. web app, admin panel, third-party services).
Example: Webhook endpoint (single trusted origin)
router.post(
"/webhook",
HiSecure.cors({
origin: ["https://trusted-client.com"],
methods: ["POST"],
allowedHeaders: ["Content-Type", "Authorization"],
credentials: true
}),
controller
);
Example: Admin dashboard with restricted origins
router.get(
"/admin/stats",
HiSecure.cors({
origin: [
"https://admin.example.com",
"https://internal.example.com"
],
credentials: true
}),
controller
);
Example: Public API with open read access
router.get(
"/public/feed",
HiSecure.cors({ origin: "*" }),
controller
);
HiSecure automatically detects validation strategy based on input type. Choose the style based on complexity and ownership.
- express-validator β quick, form-like validation
- Zod β complex schemas, reuse, shared contracts
import { HiSecure , body } from "hi-secure";
router.post(
"/register",
HiSecure.validate([
body("email")
.notEmpty()
.isEmail(),
body("password")
.isLength({ min: 6 }),
body("role")
.optional()
.isIn(["user", "admin"])
]),
controller
);
import { HiSecure , z } from "hi-secure";
const registerSchema = z.object({
email: z.string().email(),
password: z.string().min(6),
role: z.enum(["user", "admin"]).optional()
});
router.post(
"/register",
HiSecure.validate(registerSchema),
controller
);
Both approaches produce a unified error response format.
Sanitization should reflect trust boundaries. Not all routes require the same level of strictness.
User-generated content (allow formatting)
router.post(
"/comment",
HiSecure.sanitize({
allowedTags: ["b", "i", "strong", "em", "a"],
allowedAttributes: {
a: ["href"]
}
}),
controller
);
Strict input (no HTML allowed)
router.post(
"/feedback",
HiSecure.sanitize({
allowedTags: [],
allowedAttributes: {}
}),
controller
);
Trusted internal pipeline (disable sanitization)
router.post(
"/internal/import",
HiSecure.sanitize(false),
controller
);
A real-world admin route combining multiple security layers. Execution order is deterministic and isolated to the route.
router.post(
"/admin/create-user",
HiSecure.auth({ roles: ["admin"] }),
HiSecure.rateLimit({ max: 3, windowMs: 10 * 60 * 1000 }),
HiSecure.cors({
origin: ["https://admin.example.com"]
}),
HiSecure.sanitize(),
HiSecure.validate([
body("email").isEmail(),
body("password").isLength({ min: 8 })
]),
controller
);
JWT support is optional. Enable it only if you want authentication features.
HiSecure.resetInstance();
HiSecure.getInstance({
auth: {
enabled: true,
jwtSecret: process.env.JWT_SECRET,
jwtExpiresIn: "1d"
}
});
This section demonstrates a complete, production-ready authentication setup using HiSecure. It covers signup, JWT login, Google login, role-based access control, and proper initialization.
- Signup using email and password
- Login using email and password (JWT-based)
- Login with Google (ID token verification) - Added Soon in Docs
- Role-based protected routes
- Optional authentication support
- Correct HiSecure bootstrap with reset rules
import express from "express";
import dotenv from "dotenv";
import { HiSecure } from "hi-secure";
import authRoutes from "./routes/auth.routes.js";
dotenv.config();
const app = express();
HiSecure.resetInstance();
HiSecure.getInstance({
auth: {
enabled: true,
jwtSecret: process.env.JWT_SECRET || "supersecret_32_chars_minimum",
jwtExpiresIn: "1d",
googleClientId: process.env.GOOGLE_CLIENT_ID // this only added if need googleLogin as well
}
});
app.use(HiSecure.middleware("api"));
app.use("/auth", authRoutes);
app.listen(3000);
Note: resetInstance() is recommended only for tests or starter templates.
It should not be used repeatedly in production runtime.
import { Router } from "express";
import {
signup,
loginWithJwt,
loginWithGoogle
} from "../controllers/auth.controller.js";
import { HiSecure } from "hi-secure";
const router = Router();
router.post("/signup", signup);
router.post("/login", loginWithJwt);
router.post("/google", loginWithGoogle);
router.get(
"/me",
HiSecure.auth(),
(req, res) => res.json({ user: req.user })
);
export default router;
import { HiSecure } from "hi-secure";
import { HttpError } from "../core/errors/HttpError.js";
import User from "../models/User.js";
const JWT_OPTIONS = {
issuer: 'hi-secure-backend',
audience: ['web-app', 'mobile-app'],
expiresIn: '7d',
subject: 'user-authentication'
};
exports.registerUser = async(req, res) => {
try {
const { name, email, password } = req.body;
const existingUser = await User.findOne({ email });
if (existingUser) {
return res.status(400).json({
error: 'User already exists'
});
}
const hashedPassword = await HiSecure.hash(password);
const user = await User.create({
name,
email,
password: hashedPassword
});
const token = HiSecure.jwt.sign({
userId: user._id.toString(),
email: user.email,
name: user.name,
role: 'user'
},
JWT_OPTIONS
);
res.status(201).json({
message: 'User registered successfully',
token,
user: {
id: user._id,
name: user.name,
email: user.email
}
});
} catch (error) {
console.error('Registration error:', error);
res.status(500).json({
error: 'Registration failed',
details: error.message
});
}
};
exports.loginUser = async(req, res) => {
try {
const { email, password } = req.body;
const user = await User.findOne({ email });
if (!user) {
return res.status(401).json({
error: 'Invalid credentials'
});
}
const isValid = await HiSecure.verify(password, user.password);
if (!isValid) {
return res.status(401).json({
error: 'Invalid credentials'
});
}
const token = HiSecure.jwt.sign({
userId: user._id.toString(),
email: user.email,
name: user.name,
role: 'user'
},
JWT_OPTIONS
);
res.json({
message: 'Login successful',
token,
user: {
id: user._id,
name: user.name,
email: user.email
}
});
} catch (error) {
console.error('Login error:', error);
res.status(500).json({
error: 'Login failed',
details: error.message
});
}
};
app.get(
"/admin",
HiSecure.auth({ roles: ["admin"] }),
(req, res) => {
res.json({ message: "Welcome Admin" });
}
);
const router = express.Router();
router.post(
'/register',
HiSecure.validate([
body("name")
.notEmpty().withMessage("Name is required")
.isLength({ min: 3 }).withMessage("Name must be at least 3 characters"),
body("email")
.notEmpty().withMessage("Email is required")
.isEmail().withMessage("Invalid email format"),
body("password")
.notEmpty().withMessage("Password is required")
.isLength({ min: 6 }).withMessage("Password must be at least 6 characters"),
]),
registerUser
);
router.post(
'/login',
HiSecure.validate([
body("email")
.notEmpty().withMessage("Email is required")
.isEmail().withMessage("Invalid email format"),
body("password")
.notEmpty().withMessage("Password is required")
]),
HiSecure.rateLimit({ max: 5, windowMs: 15 * 60 * 1000 }),
loginUser
);
router.get(
'/profile',
HiSecure.auth({ required: true }),
getProfile
);
router.post('/create', HiSecure.auth({ required: true }), createTask)
router.get('/get', HiSecure.auth({ required: true }), getTask)
router.put('/:id', HiSecure.auth({ required: true }), updateTask)
router.psot('/health',heatlh);
HiSecure does not require JWT options for most use cases. Default configuration provided during initialization is sufficient.
HiSecure.getInstance({
auth: {
enabled: true,
jwtSecret: process.env.JWT_SECRET,
jwtExpiresIn: "1d"
}
});
Advanced JWT options can be provided only when needed:
HiSecure.jwt.sign(
{
userId: user.id,
roles: user.roles
},
{
issuer: "my-app",
audience: ["web", "mobile"],
subject: "user-auth",
expiresIn: "7d"
}
);
JWT options are optional and intended for advanced authentication scenarios.
- Initialize HiSecure once during application startup
- Use resetInstance only for tests or starter templates
- Do not initialize HiSecure inside controllers
- Google login is used for identity verification only
- Authorization is enforced using JWT payload and roles
HiSecure provides a complete, opinionated security layer for Express. It focuses on correctness, safety and developer productivity.
One dependency. One middleware. Complete security.
Advanced patterns, RBAC strategies, adapter extensions and deployment guides will be added over time.