nestjs-xsecurity
v1.0.2
Published
Security middleware for NestJS applications with token validation and rate limiting
Downloads
203
Maintainers
Readme
nestjs-xsecurity
🔐 Robust security middleware for NestJS applications with token validation, rate limiting, and path exclusion.
📦 Installation
# Using npm
npm install nestjs-xsecurity
# Using yarn
yarn add nestjs-xsecurity
# Using pnpm
pnpm add nestjs-xsecurity
📖 Documentation
- Quick Start Guide (below)
- Complete Documentation - Visit the Wiki for:
- Advanced Configuration Examples
- Security Best Practices
- Troubleshooting
- And More!
🌟 Features
Token-based Security
- HMAC-SHA256 signature validation
- Configurable token expiration
- Custom header support
Rate Limiting
- IP-based request throttling
- Configurable attempt limits
- Automatic cleanup of expired records
Path Control
- Exclude specific routes
- Support for wildcards and patterns
- RegExp compatibility
Developer Experience
- Full TypeScript support
- Comprehensive configuration options
- CLI setup tool
- Cross-platform token generators
- Wiki documentation. Wiki
🚀 Quick Start
1. Initialize with CLI
npx nestjs-xsecurity install
This command will:
- Generate a secure random secret
- Set up environment variables
- Create initial configuration
2. Module Registration
Choose one of these approaches:
⭐ Recommended: Async Configuration
import { Module } from '@nestjs/common';
import { ConfigModule, ConfigService } from '@nestjs/config';
import { XSecurityModule } from 'nestjs-xsecurity';
@Module({
imports: [
ConfigModule.forRoot(),
XSecurityModule.registerAsync({
imports: [ConfigModule],
inject: [ConfigService],
useFactory: (config: ConfigService) => ({
enabled: config.get('XSECURITY_ENABLED', true),
secret: config.get('XSECURITY_SECRET'),
rateLimit: {
enabled: config.get('XSECURITY_RATE_LIMIT_ENABLED', true),
maxAttempts: config.get('XSECURITY_MAX_ATTEMPTS', 5),
decayMinutes: config.get('XSECURITY_DECAY_MINUTES', 1),
storeLimit: config.get('XSECURITY_RATE_LIMIT_STORE_LIMIT', 10000),
},
exclude: ['/health', '/metrics', '/api/docs/*'],
}),
}),
],
})
export class AppModule {}
Alternative: Static Configuration
import { Module } from '@nestjs/common';
import { XSecurityModule } from 'nestjs-xsecurity';
@Module({
imports: [
XSecurityModule.register({
enabled: true,
secret: process.env.XSECURITY_SECRET,
rateLimit: {
enabled: true,
maxAttempts: 5,
decayMinutes: 1,
},
exclude: ['/health'],
}),
],
})
export class AppModule {}
🔧 Configuration
Environment Variables
Details configuration options can be found in this Wiki Page.
# Required
XSECURITY_SECRET=your-secure-secret-key
# Optional
XSECURITY_ENABLED=true
XSECURITY_MAX_ATTEMPTS=5
XSECURITY_DECAY_MINUTES=1
Configuration Options
interface XSecurityConfig {
// Enable/disable middleware
enabled?: boolean;
// Your secret key for token validation
secret?: string;
// Rate limiting settings
rateLimit?: {
enabled?: boolean; // Default: true
maxAttempts?: number; // Default: 5
decayMinutes?: number; // Default: 1
cleanupInterval?: number; // Default: 5
storeLimit?: number; // Default: 10000
};
// Token configuration
token?: {
headerName?: string; // Default: 'X-SECURITY-TOKEN'
expirySeconds?: number; // Default: 10 (10 seconds)
};
// Paths to exclude from security checks
exclude?: Array<string | RegExp>;
// Custom error messages
errorMessages?: {
rateLimitExceeded?: string;
invalidToken?: string;
};
}
🔑 Token Implementation
Node.js / TypeScript
import crypto from 'crypto';
function generateXsecurityToken(secretKey: string, expirySeconds = 300): string {
const expiryTimestamp = Math.floor(Date.now() / 1000) + expirySeconds;
const randomBytes = crypto.randomBytes(16).toString('hex'); // Add randomness
const payload = {
expiry: expiryTimestamp,
nonce: randomBytes,
iat: Date.now()
};
const token = Buffer.from(JSON.stringify(payload)).toString('base64');
const signature = crypto
.createHmac('sha256', secretKey)
.update(token)
.digest('hex');
return `${token}.${signature}`;
}
// Usage
const token = generateXsecurityToken('your-secret-key');
Python
import time
import json
import hmac
import base64
import secrets
import hashlib
from typing import Optional
def generate_xsecurity_token(secret_key: str, expiry_seconds: int = 300) -> str:
"""
Generate a secure token with expiry and nonce.
Args:
secret_key (str): Secret key for signing
expiry_seconds (int): Token validity duration in seconds
Returns:
str: Generated security token
"""
expiry_timestamp = int(time.time()) + expiry_seconds
random_bytes = secrets.token_hex(16) # 16 bytes = 32 hex chars
payload = {
"expiry": expiry_timestamp,
"nonce": random_bytes,
"iat": int(time.time() * 1000) # milliseconds
}
# Convert payload to base64
token = base64.b64encode(
json.dumps(payload).encode('utf-8')
).decode('utf-8')
# Generate signature
signature = hmac.new(
secret_key.encode('utf-8'),
token.encode('utf-8'),
hashlib.sha256
).hexdigest()
return f"{token}.{signature}"
Flutter / Dart
import 'dart:convert';
import 'dart:math';
import 'package:crypto/crypto.dart';
class XSecurityToken {
static String generate(String secretKey, {int expirySeconds = 300}) {
final expiryTimestamp = (DateTime.now().millisecondsSinceEpoch ~/ 1000) + expirySeconds;
// Generate random bytes for nonce
final random = Random.secure();
final randomBytes = List<int>.generate(16, (i) => random.nextInt(256));
final nonce = randomBytes.map((byte) => byte.toRadixString(16).padLeft(2, '0')).join();
final payload = {
'expiry': expiryTimestamp,
'nonce': nonce,
'iat': DateTime.now().millisecondsSinceEpoch
};
// Convert payload to base64
final token = base64Encode(utf8.encode(jsonEncode(payload)));
// Generate signature
final hmacSha256 = Hmac(sha256, utf8.encode(secretKey));
final signature = hmacSha256.convert(utf8.encode(token)).toString();
return '$token.$signature';
}
}
📝 Examples
Making a Secured Request
// Client-side
const token = generateXsecurityToken(secretKey);
await fetch('https://api.example.com/data', {
headers: {
'X-SECURITY-TOKEN': token
}
});
Path Exclusion Patterns
XSecurityModule.register({
exclude: [
'/health', // Exact match
'/api/*', // Wildcard match
'/v1/:param/data', // Parameter match
/^\/public\/.*/ // RegExp match
]
});
Error Responses
// Rate limit exceeded
{
"statusCode": 429,
"message": "Too many requests. Please try again later.",
"error": "Too Many Requests"
}
// Invalid token
{
"statusCode": 403,
"message": "Invalid XSECURITY token",
"error": "Forbidden"
}
🛠️ CLI Reference
npx nestjs-xsecurity <command>
Commands:
install Initialize security configuration
init Alias for install
help Show help information
🔒 Security Best Practices
Secret Management
- Use environment variables for secrets
- Never expose secrets in client code
Rate Limiting
- Adjust limits based on your API's capacity
- Monitor rate limit hits
- Implement progressive delays
🤝 Contributing
Contributions are welcome! Please read our contributing guidelines before submitting changes.
📄 License
This project is licensed under the MIT License - see the LICENSE file for details.
✨ Creator
Made with ❤️ for the NestJS community