Retrofit de Spring Security: cuando la VPN deja de ser la capa de autorización
Un proyecto de demostración en Java 21 y Spring Boot 3.5 documenta los fallos reales que aparecen al añadir autenticación a una aplicación que siempre vivió detrás de la red corporativa.

Durante años, la respuesta a "¿quién puede llegar a esta aplicación?" cabía en una palabra: la red. Cuando ese perímetro se disuelve —un auditor externo necesita acceso de lectura dos semanas, un socio quiere ver sus propias cifras, alguien monta un cliente móvil—, el sistema tiene que responder en cada petición lo que antes respondía la VPN una sola vez en la puerta: quién eres (401 sin identidad válida) y si puedes tocar estos datos (403 con identidad válida y permisos insuficientes). Un proyecto de demostración en Java 21 y Spring Boot 3.5 cuenta cómo se hace ese retrofit y, sobre todo, lo que la red estaba tapando.
Autenticación es un fin de semana; el aislamiento de datos, no
La primera mitad del trabajo es configuración: JWT con access tokens de 15 minutos y refresh tokens de 7 días, el filtro, las reglas por endpoint. Está bien documentado y es casi mecánico. La segunda mitad es un problema de diseño que toca cada ruta de lectura del código.
Dentro de la VPN, todos los métodos de servicio se escribieron bajo una suposición tácita: quien llama tiene derecho a ver esto. getAllBankAccounts() devuelve todas las cuentas. findByBankId(bankId) devuelve todas las cuentas de ese banco. Nadie escribió un WHERE organization_id = ? porque no había nada de lo que defenderse. Publica eso detrás de un formulario de login y cada uno de esos métodos se convierte en un IDOR: un usuario perfectamente autenticado de la organización A llama a un endpoint legítimo y lee el historial de pagos de la organización B. Sin exploit ni ataque ingenioso; un GET con un token válido. Añadir la pantalla de login no arregla el problema, le da a cada atacante una identidad legítima con la que atacar.
La identidad que emites decide lo difícil que será el resto
Ahí está la decisión que sostiene la segunda mitad: la organización del llamante viaja dentro de la identidad. El token lleva un claim orgId al emitirse y el principal es un record con userId, email, rol y organizationId, no un simple nombre de usuario. Como el inquilino va pegado a la identidad, cualquier servicio puede preguntar qué organización está llamando sin tocar la base de datos y sin arrastrar un parámetro por quince firmas de método. El código de esa pieza está en JwtService.java.
El sistema es una demo: contabilidad financiera con organizaciones, contrapartes, cuentas bancarias y documentos contabilizados y revertidos sobre un libro event-sourced, con despliegue público. No hay clientes ni dinero reales, y organizaciones, contrapartes y pagos están fabricados. La forma de esa base de datos no: esos son los muebles que hacen que la autorización sea de verdad difícil.
El autor es explícito con el origen del material. Ninguno de los fallos está inventado para enseñar: todos están modelados sobre bugs reales de proyectos reales, la mayoría de un trabajo que terminó en mayo y cuyo código no podía publicar. Aquí sí puede romper el sistema en público. El código completo está en el repositorio de GitHub.
Lo interesante, viene a decir, no es el código de autenticación, que está documentado hasta el aburrimiento. Es todo lo que el perímetro llevaba años tapando sin que nadie lo mirara. Quien vaya a meter Spring Security en una aplicación que ya existe debería empezar por ahí: por inventariar qué métodos asumen que el que llama es un compañero.


