Advanced

Security

Secure your CanxJS applications with built-in security features and best practices.

Security Headers

XSS, CSRF, Content-Type protection

Rate Limiting

Built-in request rate limiting

Password Hashing

Argon2id/bcrypt via Bun

Input Validation

Schema-based validation

Security Middleware

app.ts
1import { createApp, security, rateLimit, cors } from "canxjs";
2
3const app = createApp({ port: 3000 });
4
5// Security headers middleware
6app.use(security({
7 xssProtection: true, // X-XSS-Protection
8 contentTypeOptions: true, // X-Content-Type-Options: nosniff
9 frameOptions: "DENY", // X-Frame-Options
10 hsts: { // Strict-Transport-Security
11 maxAge: 31536000,
12 includeSubDomains: true
13 },
14 contentSecurityPolicy: "default-src 'self'",
15 referrerPolicy: "strict-origin-when-cross-origin"
16}));
17
18// Rate limiting
19app.use(rateLimit({
20 windowMs: 60000, // 1 minute
21 max: 100 // 100 requests per minute
22}));
23
24// CORS configuration
25app.use(cors({
26 origin: ["https://example.com"],
27 methods: ["GET", "POST", "PUT", "DELETE"],
28 credentials: true
29}));

Authentication

auth.ts
1import { MiddlewareHandler } from "canxjs";
2
3export const authMiddleware: MiddlewareHandler = async (req, res, next) => {
4 const token = req.header("authorization")?.replace("Bearer ", "");
5
6 if (!token) {
7 return res.status(401).json({
8 error: "Authentication required",
9 code: "MISSING_TOKEN"
10 });
11 }
12
13 try {
14 // Verify JWT token
15 const payload = await verifyJWT(token, process.env.JWT_SECRET!);
16
17 // Store user in request context
18 req.context.set("user", payload);
19 req.context.set("userId", payload.sub);
20
21 return next();
22 } catch (error) {
23 return res.status(401).json({
24 error: "Invalid or expired token",
25 code: "INVALID_TOKEN"
26 });
27 }
28};
29
30// Protected routes
31app.get("/api/profile", authMiddleware, profileHandler);
32app.group("/api/admin", (router) => {
33 router.middleware(authMiddleware, adminMiddleware);
34 router.get("/users", listUsers);
35});

Password Hashing

passwords.ts
1// Using Bun's built-in password hashing
2const hash = async (password: string) => {
3 return await Bun.password.hash(password, {
4 algorithm: "argon2id", // or "bcrypt"
5 memoryCost: 65536,
6 timeCost: 3
7 });
8};
9
10const verify = async (password: string, hash: string) => {
11 return await Bun.password.verify(password, hash);
12};
13
14// Usage
15app.post("/register", async (req, res) => {
16 const { email, password } = await req.body();
17
18 const hashedPassword = await hash(password);
19 const user = await User.create({ email, password: hashedPassword });
20
21 return res.status(201).json({ user });
22});
23
24app.post("/login", async (req, res) => {
25 const { email, password } = await req.body();
26 const user = await User.query().where("email", "=", email).first();
27
28 if (!user || !await verify(password, user.password)) {
29 return res.status(401).json({ error: "Invalid credentials" });
30 }
31
32 const token = await signJWT({ sub: user.id }, { expiresIn: "7d" });
33 return res.json({ token });
34});

Input Validation

validation.ts
1import { validate } from "canxjs";
2
3app.post("/users", async (req, res) => {
4 const data = await req.body();
5
6 const result = validate(data, {
7 name: ["required", "string", "min:2", "max:100"],
8 email: ["required", "email"],
9 password: ["required", "string", "min:8"],
10 age: ["number", "min:18"]
11 });
12
13 if (!result.valid) {
14 return res.status(400).json({
15 error: "Validation failed",
16 details: Object.fromEntries(result.errors)
17 });
18 }
19
20 const user = await User.create(result.data);
21 return res.status(201).json(user);
22});

CSRF Protection

csrf.ts
1import { csrf } from "canxjs";
2
3// Apply CSRF protection
4app.use(csrf({
5 cookie: true,
6 cookieName: "_csrf",
7 headerName: "x-csrf-token"
8}));
9
10// CSRF token endpoint
11app.get("/api/csrf-token", (req, res) => {
12 return res.json({ token: req.context.get("csrfToken") });
13});

Best Practices

best-practices.ts
1// Environment variables
2const config = {
3 jwtSecret: process.env.JWT_SECRET!,
4 dbPassword: process.env.DB_PASSWORD!,
5 apiKey: process.env.API_KEY!
6};
7
8// Never log sensitive data
9app.use(async (req, res, next) => {
10 console.log(`${req.method} ${req.path}`);
11 // DON'T: console.log(req.header("authorization"))
12 return next();
13});
14
15// Secure cookies
16res.cookie("session", token, {
17 httpOnly: true, // Not accessible via JavaScript
18 secure: true, // HTTPS only
19 sameSite: "Strict",
20 maxAge: 86400
21});
22
23// Sanitize user input before database
24const sanitized = input.replace(/<[^>]*>/g, "");

Next Steps

Ready to deploy? Learn how to run CanxJS in production.