feat(auth): revocación server-side de tokens JWT (denylist) - #69
Merged
Conversation
- Cada JWT incluye claim jti (UUID) para revocación individual. - Tabla tokens_revocados (Flyway V4) + entidad + repositorio. - JwtAuthenticationFilter: tras validar firma, rechaza tokens cuyo jti esté en la denylist o emitidos antes del último cambio de contraseña. - Logout revoca el token server-side además de borrar la cookie. - resetPassword invalida todas las sesiones previas del usuario (marcador por email: tokens emitidos antes del cambio -> 401). - Purge periódico de tokens expirados (@scheduled, cada hora en :30). - TokenRevocationIntegrationTest: 4 escenarios (logout revoca, token vigente autentica, ruta protegida 401 tras logout, resetPassword invalida sesiones previas). 181 tests verdes, coverage gate OK (>=70%).
The derived deleteByEmail deferred the DELETE SQL to flush, so the deterministic marker insert (jti=SHA-256(email)) collided with the existing row on the second consecutive password reset for the same user, raising a unique constraint violation masked as a 401. Execute the delete as a bulk JPQL query so the DELETE runs before the marker INSERT. Add a regression test for the double-reset scenario.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Closes #57
PR Type
Summary
jti(UUID) para revocación individual.tokens_revocados(migración Flyway V4) + entidad + repositorio.JwtAuthenticationFilter: tras validar la firma, rechaza tokens cuyojtiesté en la denylist o emitidos antes del último cambio de contraseña (401 anónimo).logout()ahora revoca el token server-side, además de borrar la cookie.resetPassword()invalida todas las sesiones previas del usuario: si te roban la cookie y cambiás la contraseña, el token robado muere.@Scheduled, cada hora).Diseño (decisión del issue)
Se eligió denylist en BD sobre refresh-token rotation, como el issue permite para una app de biblioteca:
jwt.secret(trade-off de JWT stateless, aceptado).iat) permite invalidar sesiones activas en resetPassword sin necesidad de rotación de refresh.Changes
src/main/resources/db/migration/V4__tokens_revocados.sqlsrc/main/java/com/libromagico/model/TokenRevocado.javasrc/main/java/com/libromagico/repository/TokenRevocadoRepository.javasrc/main/java/com/libromagico/service/TokenRevocationService.javasrc/main/java/com/libromagico/security/JwtTokenProvider.javajti+ getters de jti/iat/expiraciónsrc/main/java/com/libromagico/security/JwtAuthenticationFilter.javasrc/main/java/com/libromagico/security/AuthController.javasrc/main/java/com/libromagico/service/UsuarioService.javasrc/test/java/com/libromagico/security/TokenRevocationIntegrationTest.javaTest Plan
mvn -B -Pcoverage verify: 181 tests (177 previos + 4 nuevos), 0 fallosContributor Checklist
status:approved)type:*labelCo-Authored-Bytrailers