"use strict"; var __importDefault = (this && this.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; }; Object.defineProperty(exports, "__esModule", { value: true }); exports.JWTService = void 0; const jsonwebtoken_1 = __importDefault(require("jsonwebtoken")); class JWTService { constructor() { this.secretKey = process.env.JWT_SECRET || 'your-secret-key'; let expiry = 86400; if (process.env.JWT_EXPIRY) { expiry = parseInt(process.env.JWT_EXPIRY); } else if (process.env.JWT_EXPIRATION) { expiry = this.parseDuration(process.env.JWT_EXPIRATION); } this.tokenExpiry = expiry; this.cookieName = 'auth_token'; if (process.env.NODE_ENV === 'production' && (!process.env.JWT_SECRET || process.env.JWT_SECRET === 'your-secret-key')) { throw new Error('JWT_SECRET environment variable must be set in production'); } } create(payload, res) { const now = Math.floor(Date.now() / 1000); const payloadWithTimestamps = { ...payload, iat: now, exp: now + this.tokenExpiry }; // Don't use expiresIn option since we're manually setting exp in payload const options = {}; const token = jsonwebtoken_1.default.sign(payloadWithTimestamps, this.secretKey, options); res.cookie(this.cookieName, token, { httpOnly: true, secure: process.env.NODE_ENV === 'production', sameSite: 'strict', maxAge: this.tokenExpiry * 1000, // Convert to milliseconds }); return token; } verify(req) { try { const token = req.cookies[this.cookieName]; if (!token) return null; const decoded = jsonwebtoken_1.default.verify(token, this.secretKey); return decoded; } catch (error) { return null; } } // Check if token needs refresh (within 25% of expiry time) shouldRefreshToken(payload) { if (!payload.exp || !payload.iat) return false; const now = Math.floor(Date.now() / 1000); const tokenAge = now - payload.iat; const tokenLifetime = payload.exp - payload.iat; const refreshThreshold = tokenLifetime * 0.75; // Refresh when 75% of lifetime has passed return tokenAge >= refreshThreshold; } // Conditionally refresh token only if needed refreshIfNeeded(payload, res) { if (this.shouldRefreshToken(payload)) { // Create new token with fresh timestamps, but same user data const freshPayload = { userId: payload.userId, authLevel: payload.authLevel, userStatus: payload.userStatus, orgId: payload.orgId }; this.create(freshPayload, res); return true; } return false; } /** * Parse duration string to seconds (e.g., "24h", "7d", "30m") * @param duration Duration string * @returns Duration in seconds */ parseDuration(duration) { const match = duration.match(/^(\d+)([smhd])$/); if (!match) { throw new Error(`Invalid duration format: ${duration}. Use format like '24h', '7d', '30m'`); } const [, value, unit] = match; const num = parseInt(value); switch (unit) { case 's': return num; // seconds case 'm': return num * 60; // minutes case 'h': return num * 60 * 60; // hours case 'd': return num * 60 * 60 * 24; // days default: throw new Error(`Unsupported duration unit: ${unit}`); } } } exports.JWTService = JWTService; //# sourceMappingURL=JWTService.js.map