jwt-manager.jsā¢6.4 kB
#!/usr/bin/env node
/**
* Centralized JWT Token Manager v1.0.0
* @description Secure, single-source JWT token management for EuConquisto Composer MCP
* @version 1.0.0
* @date January 2025
* @security Single secure location, no fallbacks for enhanced security
*/
import { readFileSync, existsSync, statSync } from 'fs';
import { join } from 'path';
import { fileURLToPath } from 'url';
import { dirname } from 'path';
const __filename = fileURLToPath(import.meta.url);
const __dirname = dirname(__filename);
// Project root detection
const PROJECT_ROOT = join(__dirname, '..', '..');
/**
* JWT Manager - Single Source of Truth for Token Management
* Security-first approach with no fallback locations
*/
export class JWTManager {
constructor() {
this.token = null;
this.tokenPath = join(PROJECT_ROOT, 'config', 'jwt-token.txt');
this.isLoaded = false;
}
/**
* Get the secure JWT token path
* @returns {string} Absolute path to JWT token file
*/
getTokenPath() {
return this.tokenPath;
}
/**
* Validate JWT token file exists and is accessible
* @returns {object} Validation result with details
*/
validateTokenFile() {
try {
// Check if file exists
if (!existsSync(this.tokenPath)) {
return {
valid: false,
error: 'JWT token file not found',
path: this.tokenPath,
suggestion: 'Ensure /config/jwt-token.txt exists'
};
}
// Check file stats
const stats = statSync(this.tokenPath);
// Basic size validation (JWT should be substantial)
if (stats.size < 100) {
return {
valid: false,
error: 'JWT token file appears empty or invalid',
size: stats.size,
path: this.tokenPath
};
}
// File appears valid
return {
valid: true,
size: stats.size,
path: this.tokenPath,
lastModified: stats.mtime
};
} catch (error) {
return {
valid: false,
error: `File access error: ${error.message}`,
path: this.tokenPath
};
}
}
/**
* Load JWT token from secure location
* @returns {string} JWT token string
* @throws {Error} If token cannot be loaded
*/
getToken() {
// Return cached token if already loaded
if (this.isLoaded && this.token) {
return this.token;
}
// Validate file first
const validation = this.validateTokenFile();
if (!validation.valid) {
throw new Error(`JWT Manager: ${validation.error}. Path: ${validation.path}`);
}
try {
// Read and validate token
const tokenContent = readFileSync(this.tokenPath, 'utf-8').trim();
if (!tokenContent) {
throw new Error('JWT token file is empty');
}
// Basic JWT format validation (should start with eyJ)
if (!tokenContent.startsWith('eyJ')) {
throw new Error('JWT token format appears invalid (should start with eyJ)');
}
// Cache successful load
this.token = tokenContent;
this.isLoaded = true;
return this.token;
} catch (error) {
throw new Error(`JWT Manager: Failed to load token - ${error.message}`);
}
}
/**
* Get token information without exposing the actual token
* @returns {object} Token metadata
*/
getTokenInfo() {
const validation = this.validateTokenFile();
if (!validation.valid) {
return {
available: false,
error: validation.error,
path: this.tokenPath
};
}
return {
available: true,
path: this.tokenPath,
size: validation.size,
lastModified: validation.lastModified,
loaded: this.isLoaded
};
}
/**
* Clear cached token (force reload on next access)
*/
clearCache() {
this.token = null;
this.isLoaded = false;
}
/**
* Check if JWT token is expired (basic check)
* @returns {object} Expiration status
*/
checkExpiration() {
try {
const token = this.getToken();
// Extract payload (basic JWT structure: header.payload.signature)
const parts = token.split('.');
if (parts.length !== 3) {
return { valid: false, error: 'Invalid JWT structure' };
}
// Decode payload (base64)
const payload = JSON.parse(Buffer.from(parts[1], 'base64').toString());
if (!payload.exp) {
return { valid: true, error: 'No expiration claim found' };
}
const now = Math.floor(Date.now() / 1000);
const expired = now > payload.exp;
const timeRemaining = payload.exp - now;
return {
valid: !expired,
expired: expired,
expirationDate: new Date(payload.exp * 1000),
timeRemaining: timeRemaining,
timeRemainingHours: Math.floor(timeRemaining / 3600)
};
} catch (error) {
return {
valid: false,
error: `Failed to check expiration: ${error.message}`
};
}
}
}
/**
* Singleton instance for application-wide use
*/
export const jwtManager = new JWTManager();
/**
* Convenience functions for backward compatibility
*/
export function getJWTToken() {
return jwtManager.getToken();
}
export function getJWTPath() {
return jwtManager.getTokenPath();
}
export function getJWTInfo() {
return jwtManager.getTokenInfo();
}
/**
* CLI usage for testing
*/
if (import.meta.url === `file://${process.argv[1]}`) {
console.log('š JWT Manager v1.0.0 - Token Information');
console.log('=' .repeat(50));
try {
const info = jwtManager.getTokenInfo();
console.log('š Token Path:', info.path);
console.log('ā
Available:', info.available);
if (info.available) {
console.log('š Size:', info.size, 'bytes');
console.log('š
Last Modified:', info.lastModified);
// Test expiration check
const expiration = jwtManager.checkExpiration();
if (expiration.valid) {
console.log('ā° Expires:', expiration.expirationDate);
console.log('ā³ Time Remaining:', expiration.timeRemainingHours, 'hours');
} else {
console.log('ā ļø Expiration Check:', expiration.error);
}
} else {
console.log('ā Error:', info.error);
}
} catch (error) {
console.error('ā JWT Manager Error:', error.message);
process.exit(1);
}
}