Autenticación
mTLS en todas partes, sin VPN. Cada tramo de esta integración, tanto las llamadas de API como las entregas de webhooks en ambos sentidos, se autentica mutuamente con certificados de cliente TLS. Encima de eso, las llamadas hacia Nexa llevan una llave de API del cliente, de modo que el certificado dice quién está llamando y la llave dice en nombre de quién.
De un vistazo
| Tramo | Dirección | Autenticación de transporte | Autenticación de aplicación |
|---|---|---|---|
| Llamadas de API de Nexa a Tesser | N→T | Certificado de cliente de Nexa, con fijación (pinning) de la huella digital | La identidad se resuelve a partir de la huella digital del certificado |
| Envíos de webhook de Nexa a Tesser | N→T | Certificado de cliente de Nexa | La identidad resuelta debe coincidir con {organizationId} en la ruta |
| Llamadas de API de Tesser a Nexa | T→N | Certificado de cliente de Tesser | Authorization: Bearer <felix_api_key>, verificado contra el campo customer |
| Envíos de webhook de Tesser a Nexa | T→N | Certificado de cliente de Tesser (compromiso de desarrollo) | Encabezado Ed25519 X-Tesser-Signature |
Nexa → Tesser (llamadas de API y envíos de webhook)
Esto se monta sobre el diseño mTLS ya existente de la plataforma Tesser para socios bancarios, así que no hay nada nuevo que construir del lado de Tesser.
- Durante el onboarding, la huella digital SHA-256 del certificado de
cliente de Nexa se registra contra la llave de API de Nexa en Tesser
(
POST /v1/keys/{id}/certificates). - El gateway de Tesser termina la conexión TLS, reenvía la huella digital del certificado de cliente y la plataforma resuelve a partir de ella la identidad de Nexa.
- La rotación es traslapada: se registra el certificado nuevo, se pasa el tráfico y recién entonces se revoca el anterior. No existe ninguna ventana en la que Nexa tenga un solo certificado válido registrado.
El receptor de webhooks [T]
agrega una verificación adicional: la identidad resuelta a partir del
certificado debe coincidir con el {organizationId} de la ruta de la
solicitud. Una discrepancia da 401. {organizationId} es el ID de
organización de Nexa en Tesser, que se comparte durante el onboarding.
Antes de enviar eventos reales, Nexa puede confirmar la conectividad y las
credenciales con
HEAD /v1/webhooks/nexa/{organizationId}
[T], que usa la misma ruta y la misma autenticación, sin cuerpo.
El mismo certificado autentica las llamadas de tesorería de Nexa:
GET /v1/accounts/{id} [T] y
POST /v1/treasury/withdrawals
[T].
Tesser → Nexa (llamadas de API)
Tesser presenta dos credenciales en cada llamada a un endpoint alojado por Nexa:
- Un certificado de cliente que identifica a Tesser como el orquestador.
Authorization: Bearer <felix_api_key>, la llave de API de Nexa del cliente, que identifica el contexto del cliente. El campocustomerdel cuerpo de la solicitud sirve para verificarla de forma cruzada.
Tener credenciales por cliente significa que incorporar más adelante a una segunda remesadora no exige rediseñar la autenticación: hace falta una llave nueva, no un esquema nuevo.
Recomendación a Nexa para validar el certificado de Tesser: fijar (pinning) la huella digital del certificado hoja (el mecanismo que la propia Tesser utiliza) o validarlo contra una CA emisora proporcionada por Tesser. Cualquiera de las dos opciones es aceptable; la decisión es de Nexa, y ambas se documentan aquí de forma deliberada para que se pueda decidir en la reunión técnica (pregunta abierta 8).
| Enfoque | Qué almacena Nexa | Rotación |
|---|---|---|
| Fijación (pinning) de la huella del certificado hoja | La huella digital SHA-256 del certificado hoja de Tesser | Tesser envía la huella digital nueva antes del cambio; Nexa mantiene ambas registradas durante el traslape y luego descarta la anterior |
| Validación contra la CA emisora | El certificado de la CA emisora de Tesser | La rotación del certificado hoja no exige ninguna acción de Nexa mientras la CA no cambie |
El intercambio de certificados y el procedimiento de rotación en sí son parte del onboarding fuera de banda, no operaciones de API. Ambas partes deben acordar el canal de contacto y la ventana de traslape antes de que se mueva el primer GTQ real.
Operaciones afectadas: crear cotización, aceptar cotización, reportar depósito, crear pago, consultar cotización, consultar pago. Todas son [N].
De Tesser a Nexa (webhooks): compromiso de desarrollo
Hoy el emisor de webhooks de Tesser firma los payloads con Ed25519 (el
encabezado X-Tesser-Signature) sobre HTTPS simple y por ahora no puede
presentar un certificado de cliente. Tesser lo va a ampliar para que
presente un certificado de cliente en las entregas hacia Nexa, de modo que
los webhooks cumplan el mismo estándar de mTLS que las llamadas de API. El
encabezado de firma Ed25519 se conserva. Ya está construido, y la protección
doble no cuesta nada.
Este trabajo corresponde a la ingeniería de plataforma de Tesser, está en la
ruta crítica del POC y se le da seguimiento como tal. Se necesita antes de
los webhooks en producción; no se necesita para el host de stubs ni para
este portal. Afecta las entregas hacia
POST /v1/webhooks/tesser
[N].
Comportamiento ante errores
Las fallas de autenticación usan el envoltorio de error compartido, con
error_code: "UNAUTHENTICATED" y HTTP 401, en ambos lados y en todas las
operaciones:
Code
Las operaciones incorporadas de la API principal de Tesser
(consultar cuenta,
crear retiro) usan en su lugar los
códigos de error propios de esa API principal, con api-0004 para un 401.
Esa diferencia es intencional: esos endpoints ya están en producción y su
contrato no se va a redefinir para este POC.
El host
Un solo entorno por ahora: un único host sirve los tres documentos de API, separados por prefijo de ruta.
| API alojada por Nexa | https://nexa-poc-main-c82e5ac.zuplo.app/nexa |
| API alojada por Tesser | https://nexa-poc-main-c82e5ac.zuplo.app/tesser |
Hoy ese host es un stub sin estado: sin mTLS, sin llaves de API, sin secuenciación. El modelo de autenticación descrito arriba corresponde a las implementaciones reales, no al stub. Ver Pruebas y stubs.