WIP: feat(security): implement refresh tokens #49

Closed
dylan wants to merge 25 commits from feat/add-refresh-tokens into master
Showing only changes of commit 47e78d0d26 - Show all commits

View File

@@ -74,7 +74,7 @@ class TokenServiceTest {
Duration.ofSeconds(10),
Duration.ofSeconds(10),
Duration.ofSeconds(10),
Duration.ofSeconds(10)
Duration.ofSeconds(5)
)
);
@@ -323,5 +323,44 @@ class TokenServiceTest {
TokenService.Rotation rotation = tokenService.rotate(rawToken);
assertNotEquals(rawToken, rotation.newRefreshToken());
}
// Grace period checks
@Test
void usedWithinGrace_returnsNewToken() {
Instant usedAt = Instant.now(clock);
TokenFamily tokenFamily = new TokenFamily();
tokenFamily.setId(1L);
tokenFamily.setUser(createUser(1L, "user", "user"));
tokenFamily.setExpiresAt(usedAt.plusSeconds(10));
RefreshToken refreshToken = new RefreshToken();
refreshToken.setTokenHash(rawToken.getBytes());
refreshToken.setTokenFamily(tokenFamily);
refreshToken.setExpiresAt(usedAt.plusSeconds(10));
refreshToken.setUsedAt(usedAt);
when(refreshTokenRepository.findByHash(any()))
.thenReturn(Optional.of(refreshToken));
// within grace: 3s since usedAt, grace is 5s, and nothing has expired yet
clock.advance(Duration.ofSeconds(3));
TokenService.Rotation rotation = tokenService.rotate(rawToken);
assertEquals(1L, rotation.userId());
assertNotEquals(rawToken, rotation.newRefreshToken());
assertNull(tokenFamily.getRevokedAt());
verify(tokenFamilyRepository, never()).save(any());
// grace is not extended by a replay, and only the new token is written
assertEquals(usedAt, refreshToken.getUsedAt());
verify(refreshTokenRepository, times(1)).save(tokenCaptor.capture());
RefreshToken newToken = tokenCaptor.getValue();
assertNull(newToken.getUsedAt());
assertSame(tokenFamily, newToken.getTokenFamily());
assertNotEquals(refreshToken.getTokenHash(), newToken.getTokenHash());
}
}
}