backend-mcp
Version:
Generador automático de backends con Node.js, Express, Prisma y módulos configurables. Servidor MCP compatible con npx para agentes IA. Soporta PostgreSQL, MySQL, MongoDB y SQLite.
201 lines (172 loc) • 5.12 kB
JavaScript
/**
* Ejemplo de API de validación JWT para Backend MCP
* Este archivo puede ser desplegado en Vercel, Netlify Functions, o cualquier serverless
*
* Para Vercel: coloca este archivo en /api/validate.js
* Para Netlify: coloca en /netlify/functions/validate.js
*/
const crypto = require('crypto');
// Configuración (usar variables de entorno en producción)
const JWT_SECRET = process.env.JWT_SECRET || 'backend-mcp-secret-key-2024';
const STRIPE_WEBHOOK_SECRET = process.env.STRIPE_WEBHOOK_SECRET;
// Base de datos simulada (usar una base de datos real en producción)
const validTokens = new Map([
// Ejemplo de tokens válidos
['demo_token_basic', {
id: 'user_1',
email: 'demo@example.com',
plan: 'basic',
permissions: ['basic'],
validUntil: Date.now() + (30 * 24 * 60 * 60 * 1000) // 30 días
}],
['demo_token_premium', {
id: 'user_2',
email: 'premium@example.com',
plan: 'premium',
permissions: ['basic', 'premium'],
validUntil: Date.now() + (30 * 24 * 60 * 60 * 1000)
}]
]);
/**
* Función principal de validación JWT
* @param {Object} req - Request object
* @param {Object} res - Response object
*/
export default async function handler(req, res) {
// Configurar CORS
res.setHeader('Access-Control-Allow-Origin', '*');
res.setHeader('Access-Control-Allow-Methods', 'POST, OPTIONS');
res.setHeader('Access-Control-Allow-Headers', 'Content-Type, Authorization');
if (req.method === 'OPTIONS') {
return res.status(200).end();
}
if (req.method !== 'POST') {
return res.status(405).json({ error: 'Método no permitido' });
}
try {
const { token } = req.body;
if (!token) {
return res.status(400).json({
valid: false,
error: 'Token requerido'
});
}
// Validar token
const user = await validateToken(token);
if (!user) {
return res.status(401).json({
valid: false,
error: 'Token inválido o expirado'
});
}
// Verificar expiración
if (user.validUntil && Date.now() > user.validUntil) {
return res.status(401).json({
valid: false,
error: 'Token expirado'
});
}
return res.status(200).json({
valid: true,
user: {
id: user.id,
email: user.email,
plan: user.plan,
permissions: user.permissions,
validUntil: user.validUntil
}
});
} catch (error) {
console.error('Error validating token:', error);
return res.status(500).json({
valid: false,
error: 'Error interno del servidor'
});
}
}
/**
* Valida un token JWT
* @param {string} token - Token a validar
* @returns {Object|null} - Usuario si es válido, null si no
*/
async function validateToken(token) {
try {
// 1. Verificar en base de datos simulada (para tokens demo)
if (validTokens.has(token)) {
return validTokens.get(token);
}
// 2. Validar JWT real
const parts = token.split('.');
if (parts.length !== 3) {
return null;
}
const header = JSON.parse(Buffer.from(parts[0], 'base64url').toString());
const payload = JSON.parse(Buffer.from(parts[1], 'base64url').toString());
const signature = parts[2];
// Verificar algoritmo
if (header.alg !== 'HS256') {
return null;
}
// Verificar firma
const expectedSignature = crypto
.createHmac('sha256', JWT_SECRET)
.update(`${parts[0]}.${parts[1]}`)
.digest('base64url');
if (signature !== expectedSignature) {
return null;
}
// Verificar issuer
if (payload.iss !== 'backend-mcp-auth') {
return null;
}
// Verificar expiración
if (payload.exp && Date.now() >= payload.exp * 1000) {
return null;
}
return {
id: payload.sub,
email: payload.email,
plan: payload.plan || 'basic',
permissions: payload.permissions || ['basic'],
validUntil: payload.exp ? payload.exp * 1000 : null
};
} catch (error) {
console.error('Token validation error:', error);
return null;
}
}
/**
* Genera un token JWT (para testing)
* @param {Object} user - Datos del usuario
* @returns {string} - Token JWT
*/
function generateToken(user) {
const header = {
alg: 'HS256',
typ: 'JWT'
};
const payload = {
iss: 'backend-mcp-auth',
sub: user.id,
email: user.email,
plan: user.plan,
permissions: user.permissions,
iat: Math.floor(Date.now() / 1000),
exp: Math.floor(Date.now() / 1000) + (30 * 24 * 60 * 60) // 30 días
};
const encodedHeader = Buffer.from(JSON.stringify(header)).toString('base64url');
const encodedPayload = Buffer.from(JSON.stringify(payload)).toString('base64url');
const signature = crypto
.createHmac('sha256', JWT_SECRET)
.update(`${encodedHeader}.${encodedPayload}`)
.digest('base64url');
return `${encodedHeader}.${encodedPayload}.${signature}`;
}
// Exportar funciones para testing
if (typeof module !== 'undefined' && module.exports) {
module.exports = {
handler,
validateToken,
generateToken
};
}