Security
Bueno provides security primitives as first-class features, all implemented using Bun's native cryptographic APIs.
JWT
Sign and verify JSON Web Tokens:import { signJwt, verifyJwt } from '@buenojs/bueno/security';
// Sign a token
const token = await signJwt(
{ userId: 1, role: 'admin' },
{ secret: process.env.JWT_SECRET!, expiresIn: '7d' }
);
// Verify and decode
const payload = await verifyJwt(token, process.env.JWT_SECRET!);
if (payload) {
console.log(payload.userId); // 1
}
JWT middleware
import { jwtMiddleware } from '@buenojs/bueno/security';
app.use(jwtMiddleware({
secret: process.env.JWT_SECRET!,
exclude: ['/auth/login', '/auth/register'],
}));
// In handlers, access the decoded payload
app.get('/me', (ctx) => {
const user = ctx.get('jwtPayload');
return ctx.json(user);
});
Password hashing
Bueno delegates toBun.password for secure bcrypt/argon2 hashing:
import { hashPassword, verifyPassword } from '@buenojs/bueno/security';
// Hash during registration
const hash = await hashPassword('user-password');
// Verify during login
const valid = await verifyPassword('user-password', hash);
if (!valid) {
return ctx.json({ error: 'Invalid credentials' }, 401);
}
Bun.password uses argon2id by default, which is resistant to GPU cracking.
CSRF protection
import { csrf } from '@buenojs/bueno/security';
app.use(csrf({
secret: process.env.CSRF_SECRET!,
cookie: 'csrf-token',
header: 'x-csrf-token',
}));
The middleware:
- Generates a signed token and sets it as a cookie on GET requests
- Validates the token from the request header on state-mutating requests (POST, PUT, PATCH, DELETE)
Rate limiting
Rate limiting is also available as security middleware:import { rateLimit } from '@buenojs/bueno/middleware';
// Global limit
app.use(rateLimit({ windowMs: 60_000, max: 100 }));
// Stricter limit on auth routes
app.post('/auth/login', loginHandler, {
middleware: [rateLimit({ windowMs: 60_000, max: 5 })],
});
Security headers
Apply a sensible set of security headers to all responses:import { securityHeaders } from '@buenojs/bueno/middleware';
app.use(securityHeaders({
contentSecurityPolicy: {
directives: {
defaultSrc: ["'self'"],
scriptSrc: ["'self'", 'cdn.tailwindcss.com'],
},
},
hsts: { maxAge: 31536000, includeSubDomains: true },
}));
Headers applied by default:
| Header | Value |
|---|---|
X-Content-Type-Options |
nosniff |
X-Frame-Options |
DENY |
X-XSS-Protection |
1; mode=block |
Referrer-Policy |
strict-origin-when-cross-origin |
Permissions-Policy |
Restrictive defaults |
API key authentication
import { apiKeyAuth } from '@buenojs/bueno/security';
app.use('/api', apiKeyAuth({
keys: new Set([process.env.API_KEY!]),
header: 'x-api-key',
}));
Best practices
- Store secrets in environment variables, never in source code
- Use
httpOnlyandsecureflags on session cookies - Always validate and sanitize user input with the validation module
- Enable rate limiting on authentication endpoints
- Use parameterized queries (never string concatenation) in database queries