Devs
February 10, 2026

Seguridad en APIs de Facturación: JWT, Certificados y Mejores Prácticas

Integrar facturación electrónica implica manejar información fiscal sensible: RFCs, certificados digitales, montos de operaciones. Un error de seguridad puede exponer datos de tus clientes o permitir la emisión fraudulenta de facturas.

Esta guía cubre las mejores prácticas de seguridad al integrar APIs de facturación CFDI, desde autenticación hasta protección de datos en tránsito y reposo.

Autenticación con JWT

La API de gigstack usa JSON Web Tokens (JWT) para autenticación. Entender cómo funcionan es crucial para una integración segura.

¿Qué es un JWT?

Un JWT es un token firmado digitalmente que contiene información sobre tu identidad y permisos. Tiene tres partes separadas por puntos:

  • Header: Algoritmo de firma y tipo de token
  • Payload: Datos del usuario/aplicación (claims)
  • Signature: Firma criptográfica que valida la integridad

Obtener tu token

Los tokens se generan desde el panel de gigstack:

  1. Accede a app.gigstack.pro/settings
  2. Ve a la sección "API Keys"
  3. Genera un nuevo token con los permisos necesarios
  4. Copia el token inmediatamente (solo se muestra una vez)

Usar el token en requests

Incluye el token en el header Authorization de cada request:

Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...

Ejemplo en código:

const response = await fetch('https://api.gigstack.io/v2/invoices', { method: 'POST', headers: { 'Authorization': 'Bearer ' + process.env.GIGSTACK_API_KEY, 'Content-Type': 'application/json' }, body: JSON.stringify(invoiceData) });

Almacenamiento seguro de credenciales

Nunca en código fuente

El error más común: hardcodear tokens en el código. Esto expone tus credenciales si el repositorio es público o se filtra.

❌ Incorrecto:

const API_KEY = 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...';

✅ Correcto:

const API_KEY = process.env.GIGSTACK_API_KEY;

Variables de entorno

Usa variables de entorno para almacenar credenciales:

# .env (nunca commitear este archivo) GIGSTACK_API_KEY=tu_token_aqui GIGSTACK_WEBHOOK_SECRET=tu_secret_aqui

Agrega .env a tu .gitignore:

# .gitignore .env .env.local .env.production

Gestores de secretos en producción

Para ambientes de producción, usa servicios especializados:

  • AWS Secrets Manager: Rotación automática, auditoría, encriptación
  • Google Secret Manager: Integrado con GCP, versionado
  • HashiCorp Vault: Self-hosted, muy configurable
  • Doppler: SaaS simple para equipos pequeños

Ejemplo con AWS Secrets Manager:

import { SecretsManagerClient, GetSecretValueCommand } from '@aws-sdk/client-secrets-manager'; const client = new SecretsManagerClient({ region: 'us-east-1' }); async function getApiKey() { const response = await client.send( new GetSecretValueCommand({ SecretId: 'gigstack/api-key' }) ); return JSON.parse(response.SecretString).apiKey; }

Manejo de certificados CSD

Los Certificados de Sello Digital (CSD) son la "firma digital" para timbrar facturas. Su protección es crítica.

¿Qué son los archivos CSD?

  • .cer: Certificado público (puede compartirse)
  • .key: Llave privada (NUNCA compartir)
  • Contraseña: Protege el archivo .key

Cómo gigstack maneja los CSD

gigstack almacena los certificados de tus usuarios de forma segura:

  • Encriptación AES-256 en reposo
  • Contraseña del .key nunca se almacena en texto plano
  • Acceso controlado por permisos de usuario
  • Auditoría de cada uso del certificado

Si manejas CSD directamente

Si tu aplicación maneja certificados (no recomendado):

// NUNCA hacer esto: const privateKey = fs.readFileSync('./certificados/clave.key'); const password = 'mi_password_123'; // ❌ Expuesto // Mejor práctica: const privateKey = await getFromSecretManager('csd/client_123/key'); const password = await getFromSecretManager('csd/client_123/password');

Seguridad en tránsito

HTTPS obligatorio

Todas las comunicaciones con la API de gigstack usan HTTPS/TLS 1.3. Nunca intentes conectar por HTTP plano.

Verifica certificados en tu cliente HTTP:

// Node.js: verificación habilitada por defecto // Solo deshabilitar en desarrollo con APIs locales if (process.env.NODE_ENV === 'production') { // fetch ya verifica certificados } // Si usas axios, nunca hacer esto en producción: // rejectUnauthorized: false ❌

Certificate pinning (opcional)

Para máxima seguridad, puedes verificar el certificado específico de gigstack:

import https from 'https'; const agent = new https.Agent({ ca: fs.readFileSync('./gigstack-ca.pem'), checkServerIdentity: (host, cert) => { // Verificar fingerprint del certificado if (cert.fingerprint !== 'AA:BB:CC:...:expected_fingerprint') { throw new Error('Certificate mismatch'); } } }); fetch('https://api.gigstack.io/v2/invoices', { agent });

Validación de webhooks

Los webhooks de gigstack incluyen una firma para verificar autenticidad.

¿Por qué validar?

Sin validación, un atacante podría enviar webhooks falsos a tu endpoint, haciéndote creer que una factura se creó cuando no fue así.

Implementación de verificación

import crypto from 'crypto'; const WEBHOOK_SECRET = process.env.GIGSTACK_WEBHOOK_SECRET; function verifyWebhookSignature(payload, signature) { const expectedSignature = crypto .createHmac('sha256', WEBHOOK_SECRET) .update(JSON.stringify(payload)) .digest('hex'); // Comparación segura contra timing attacks return crypto.timingSafeEqual( Buffer.from(signature), Buffer.from(expectedSignature) ); } app.post('/webhooks/gigstack', (req, res) => { const signature = req.headers['x-gigstack-signature']; if (!signature) { console.warn('Webhook sin firma recibido'); return res.status(401).json({ error: 'Missing signature' }); } if (!verifyWebhookSignature(req.body, signature)) { console.warn('Webhook con firma inválida'); return res.status(401).json({ error: 'Invalid signature' }); } // Firma válida, procesar webhook processWebhook(req.body); res.status(200).json({ received: true }); });

Protección de datos fiscales

Datos sensibles a proteger

  • RFC: Identificador fiscal único
  • Razón social: Nombre legal de la empresa
  • Domicilio fiscal: Dirección registrada ante SAT
  • Montos: Información financiera de transacciones
  • UUIDs: Identificadores de facturas

Encriptación en reposo

Si almacenas datos fiscales en tu base de datos, encripta los campos sensibles:

import crypto from 'crypto'; const ENCRYPTION_KEY = Buffer.from(process.env.ENCRYPTION_KEY, 'hex'); const IV_LENGTH = 16; function encrypt(text) { const iv = crypto.randomBytes(IV_LENGTH); const cipher = crypto.createCipheriv('aes-256-cbc', ENCRYPTION_KEY, iv); let encrypted = cipher.update(text, 'utf8', 'hex'); encrypted += cipher.final('hex'); return iv.toString('hex') + ':' + encrypted; } function decrypt(text) { const [ivHex, encrypted] = text.split(':'); const iv = Buffer.from(ivHex, 'hex'); const decipher = crypto.createDecipheriv('aes-256-cbc', ENCRYPTION_KEY, iv); let decrypted = decipher.update(encrypted, 'hex', 'utf8'); decrypted += decipher.final('utf8'); return decrypted; } // Uso const rfcEncrypted = encrypt('XAXX010101000'); await db.clients.create({ rfc_encrypted: rfcEncrypted }); // Lectura const client = await db.clients.findOne({ id: 123 }); const rfc = decrypt(client.rfc_encrypted);

Logging sin datos sensibles

Nunca loguees datos fiscales completos:

// ❌ Incorrecto console.log('Creando factura para:', client.rfc, client.razonSocial); // ✅ Correcto console.log('Creando factura para cliente:', client.id); console.log('RFC:', maskRFC(client.rfc)); // XAXX****1000 function maskRFC(rfc) { return rfc.substring(0, 4) + '****' + rfc.substring(rfc.length - 4); }

Rate limiting y protección contra abuso

Límites de la API

gigstack aplica rate limiting para proteger la infraestructura:

  • Requests por minuto: 100 (plan estándar)
  • Facturas por hora: 500
  • Requests concurrentes: 10

Manejo de errores 429

async function requestWithRetry(endpoint, options, maxRetries = 3) { for (let attempt = 1; attempt <= maxRetries; attempt++) { const response = await fetch(endpoint, options); if (response.status === 429) { const retryAfter = response.headers.get('Retry-After') || 60; console.log('Rate limited, esperando ' + retryAfter + ' segundos...'); await sleep(retryAfter * 1000); continue; } return response; } throw new Error('Max retries exceeded'); } function sleep(ms) { return new Promise(resolve => setTimeout(resolve, ms)); }

Implementa rate limiting en tu lado

Protege tu propio endpoint de webhooks:

import rateLimit from 'express-rate-limit'; const webhookLimiter = rateLimit({ windowMs: 60 * 1000, // 1 minuto max: 100, // máximo 100 requests message: { error: 'Too many requests' } }); app.post('/webhooks/gigstack', webhookLimiter, (req, res) => { // ... });

Auditoría y monitoreo

Logs de acceso a la API

Mantén registro de todas las operaciones fiscales:

async function createInvoiceWithAudit(invoiceData, userId) { const startTime = Date.now(); try { const invoice = await createInvoice(invoiceData); await db.auditLog.create({ action: 'invoice.create', user_id: userId, resource_id: invoice.uuid, client_rfc: maskRFC(invoiceData.clientRfc), amount: invoice.total, status: 'success', duration_ms: Date.now() - startTime, ip_address: req.ip, user_agent: req.headers['user-agent'], timestamp: new Date() }); return invoice; } catch (error) { await db.auditLog.create({ action: 'invoice.create', user_id: userId, status: 'error', error_message: error.message, duration_ms: Date.now() - startTime, timestamp: new Date() }); throw error; } }

Alertas de seguridad

Configura alertas para eventos sospechosos:

  • Múltiples facturas canceladas en poco tiempo
  • Intentos de acceso con tokens inválidos
  • Requests desde IPs inusuales
  • Picos anormales de facturación

Checklist de seguridad

  • ✅ API keys en variables de entorno, nunca en código
  • ✅ .env agregado a .gitignore
  • ✅ Gestor de secretos en producción
  • ✅ HTTPS en todas las comunicaciones
  • ✅ Validación de firma en webhooks
  • ✅ Encriptación de datos fiscales en reposo
  • ✅ Logs sin datos sensibles expuestos
  • ✅ Rate limiting implementado
  • ✅ Auditoría de operaciones fiscales
  • ✅ Alertas de seguridad configuradas

Recursos adicionales

La seguridad en facturación electrónica no es opcional. Una brecha puede resultar en emisión fraudulenta de facturas, exposición de datos fiscales de clientes, y problemas legales serios. Implementa estas prácticas desde el día uno de tu integración.

Blogs que te pueden gustar