JWT, AES-256-GCM sessions, scrypt vault, rate limiting, XSS sanitizer, CSRF, CORS, CSP — all built in, no plugins needed.
Street includes a complete security layer built on node:crypto. No third-party auth libraries — every primitive is implemented directly.
1
2
3
4
5
6
7
8
9
10
import { JwtService, container } from '@streetjs/core';
const jwt = new JwtService(process.env['JWT_SECRET']!);
container.register(JwtService, jwt);
// Sign a token (default 7 days)
const token = jwt.sign({ userId: '123', roles: ['admin'] }, '7d');
// Verify — throws if invalid or expired
const payload = jwt.verify(token) as { userId: string; roles: string[] };
Auth middleware:
1
2
3
4
5
6
7
import { authMiddleware, requireRoles } from '@streetjs/core';
// Require valid JWT on all routes
app.use(authMiddleware);
// Require specific role
app.use(requireRoles('admin'));
Or per-controller:
1
2
3
4
5
6
7
8
9
10
11
import { UnauthorizedException, container, JwtService } from '@streetjs/core';
import type { StreetContext } from '@streetjs/core';
async function authenticate(ctx: StreetContext, next: () => Promise<void>) {
const auth = ctx.headers['authorization'];
if (!auth?.startsWith('Bearer ')) throw new UnauthorizedException();
const jwt = container.resolve(JwtService);
const payload = jwt.verify(auth.slice(7));
ctx.user = payload as StreetContext['user'];
await next();
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
import { SessionManager, container } from '@streetjs/core';
const sessions = new SessionManager(process.env['SESSION_KEY']!);
container.register(SessionManager, sessions);
// Encrypt session data
const blob = sessions.encrypt({ userId: '123', roles: ['user'] });
// Set as cookie
ctx.setCookie('session', blob, {
httpOnly: true,
secure: true,
sameSite: 'Lax',
maxAge: 86400,
});
// Decrypt on subsequent requests
const session = sessions.decrypt(ctx.cookie('session') ?? '');
Generate a session key:
1
node -e "console.log(require('crypto').randomBytes(32).toString('hex'))"
Sliding-window rate limiter with BigInt nanosecond precision:
1
2
3
4
5
6
7
8
9
10
11
import { RateLimiter } from '@streetjs/core';
const limiter = new RateLimiter({
windowMs: 60_000, // 1-minute window
maxRequests: 100, // max 100 requests per IP per window
});
app.use(limiter.middleware());
// Clean up on shutdown
process.once('SIGTERM', () => limiter.destroy());
The limiter tracks up to 100K IPs and 1K timestamps per IP. Stale entries are swept periodically to prevent unbounded growth.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
import { xssMiddleware, sanitizeDeep, sanitizeString } from '@streetjs/core';
// Global middleware — sanitizes all request bodies
app.use(xssMiddleware);
// Manual sanitization
const clean = sanitizeString('<script>alert(1)</script>Hello');
// → 'Hello'
const cleanObj = sanitizeDeep({
name: '<b>Alice</b>',
bio: 'Hello <script>evil()</script> world',
});
// → { name: 'Alice', bio: 'Hello world' }
1
2
3
import { securityHeaders } from '@streetjs/core';
app.use(securityHeaders);
Sets:
X-Content-Type-Options: nosniffX-Frame-Options: DENYX-XSS-Protection: 1; mode=blockStrict-Transport-Security: max-age=31536000; includeSubDomainsReferrer-Policy: strict-origin-when-cross-originPermissions-Policy: geolocation=(), microphone=(), camera=()1
2
3
4
5
6
7
import { corsMiddleware } from '@streetjs/core';
// Allow specific origins
app.use(corsMiddleware(['https://app.example.com', 'https://admin.example.com']));
// Allow all origins (development only)
app.use(corsMiddleware(['*']));
For encrypting secrets at rest (e.g. database passwords in config files):
1
2
3
4
5
6
7
8
9
10
11
12
13
14
import { encryptSecret, decryptSecret, loadConfig } from '@streetjs/core';
// Encrypt a secret with a Key Encryption Key
const encrypted = await encryptSecret('my-db-password', process.env['KEK']!);
// → 'enc:v1:...' (store this in your config file)
// Decrypt at runtime
const dbPassword = await decryptSecret(encrypted, process.env['KEK']!);
// Or load an entire config object, decrypting all 'enc:v1:...' values
const config = await loadConfig({
pgPassword: 'enc:v1:...',
jwtSecret: 'enc:v1:...',
}, process.env['KEK']!);
Generate a KEK:
1
node -e "console.log(require('crypto').randomBytes(32).toString('hex'))"
Before going to production:
JWT_SECRET is at least 32 random characters — never a dictionary wordSESSION_KEY is a 64-character hex string (32 random bytes)KEK is set if using vault modeNODE_ENV=production is setcorsMiddleware lists only your actual frontend origins — not ['*']securityHeaders middleware is applied globallyxssMiddleware is applied globally.env is in .gitignore