web-vuln-scanner
Version:
Advanced, lightweight web vulnerability scanner with smart detection and easy-to-use interface
219 lines (188 loc) • 5.7 kB
JavaScript
/**
* JWT Token Management System
* Enterprise-grade JWT token creation, validation, and management
*/
const jwt = require('jsonwebtoken');
const crypto = require('crypto');
const { ConfigManager } = require('../config/config-manager');
const { Logger } = require('../monitoring/logger');
class JWTManager {
constructor() {
this.config = ConfigManager.getInstance();
this.logger = new Logger(this.config.get('logging'));
// Generate secure JWT secrets if not configured
this.accessTokenSecret = this.config.get('auth.jwt.accessSecret') || this.generateSecret();
this.refreshTokenSecret = this.config.get('auth.jwt.refreshSecret') || this.generateSecret();
// Token expiration settings
this.accessTokenExpiry = this.config.get('auth.jwt.accessExpiry', '15m');
this.refreshTokenExpiry = this.config.get('auth.jwt.refreshExpiry', '7d');
// Algorithm and options
this.algorithm = this.config.get('auth.jwt.algorithm', 'HS256');
this.issuer = this.config.get('auth.jwt.issuer', 'web-vuln-scanner');
this.audience = this.config.get('auth.jwt.audience', 'web-vuln-scanner-api');
}
/**
* Generate a cryptographically secure secret
*/
generateSecret() {
return crypto.randomBytes(64).toString('hex');
}
/**
* Create access token with user payload
*/
createAccessToken(user) {
try {
const payload = {
userId: user.id,
email: user.email,
roles: user.roles || [],
permissions: user.permissions || [],
type: 'access'
};
const options = {
expiresIn: this.accessTokenExpiry,
issuer: this.issuer,
audience: this.audience,
algorithm: this.algorithm,
jwtid: crypto.randomUUID(),
subject: user.id.toString()
};
return jwt.sign(payload, this.accessTokenSecret, options);
} catch (error) {
this.logger.error('Failed to create access token', { error: error.message, userId: user.id });
throw new Error('Token creation failed');
}
}
/**
* Create refresh token
*/
createRefreshToken(user) {
try {
const payload = {
userId: user.id,
type: 'refresh',
tokenFamily: crypto.randomUUID() // For token rotation
};
const options = {
expiresIn: this.refreshTokenExpiry,
issuer: this.issuer,
audience: this.audience,
algorithm: this.algorithm,
jwtid: crypto.randomUUID(),
subject: user.id.toString()
};
return jwt.sign(payload, this.refreshTokenSecret, options);
} catch (error) {
this.logger.error('Failed to create refresh token', { error: error.message, userId: user.id });
throw new Error('Refresh token creation failed');
}
}
/**
* Verify access token
*/
verifyAccessToken(token) {
try {
const options = {
issuer: this.issuer,
audience: this.audience,
algorithms: [this.algorithm]
};
const decoded = jwt.verify(token, this.accessTokenSecret, options);
if (decoded.type !== 'access') {
throw new Error('Invalid token type');
}
return decoded;
} catch (error) {
this.logger.warn('Access token verification failed', { error: error.message });
throw new Error('Invalid access token');
}
}
/**
* Verify refresh token
*/
verifyRefreshToken(token) {
try {
const options = {
issuer: this.issuer,
audience: this.audience,
algorithms: [this.algorithm]
};
const decoded = jwt.verify(token, this.refreshTokenSecret, options);
if (decoded.type !== 'refresh') {
throw new Error('Invalid token type');
}
return decoded;
} catch (error) {
this.logger.warn('Refresh token verification failed', { error: error.message });
throw new Error('Invalid refresh token');
}
}
/**
* Create token pair (access + refresh)
*/
createTokenPair(user) {
return {
accessToken: this.createAccessToken(user),
refreshToken: this.createRefreshToken(user),
tokenType: 'Bearer',
expiresIn: this.accessTokenExpiry
};
}
/**
* Decode token without verification (for debugging)
*/
decodeToken(token) {
try {
return jwt.decode(token, { complete: true });
} catch (error) {
this.logger.error('Failed to decode token', { error: error.message });
return null;
}
}
/**
* Check if token is expired
*/
isTokenExpired(token) {
try {
const decoded = this.decodeToken(token);
if (!decoded || !decoded.payload.exp) {
return true;
}
return Date.now() >= decoded.payload.exp * 1000;
} catch (error) {
return true;
}
}
/**
* Extract user ID from token
*/
extractUserId(token) {
try {
const decoded = this.decodeToken(token);
return decoded?.payload?.userId || null;
} catch (error) {
return null;
}
}
/**
* Blacklist token (requires external storage implementation)
*/
async blacklistToken(token, reason = 'manual_revocation') {
const decoded = this.decodeToken(token);
if (!decoded) {
throw new Error('Invalid token format');
}
const blacklistEntry = {
jti: decoded.payload.jti,
userId: decoded.payload.userId,
exp: decoded.payload.exp,
reason,
timestamp: new Date()
};
this.logger.info('Token blacklisted', blacklistEntry);
// TODO: Store in database/cache
// await this.tokenBlacklistStore.add(blacklistEntry);
return blacklistEntry;
}
}
module.exports = { JWTManager };