UNPKG

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
/** * 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 }; }