Add refresh token functionality and related configurations#61
Merged
Conversation
Test Results134 tests 134 ✅ 2s ⏱️ Results for commit 9d3a618. ♻️ This comment has been updated with latest results. |
Contributor
There was a problem hiding this comment.
Pull request overview
This PR adds a persistent refresh-token mechanism to the authentication system, including token issuance, rotation (with reuse detection), revocation, a refresh endpoint, and configuration for refresh-token TTL.
Changes:
- Introduces
RefreshTokenpersistence + repository/service logic for issuing, rotating, and revoking refresh tokens. - Updates auth flows (sign-in/up, refresh, logout) and adds
/api/v1/auth/refreshAPI + related DTOs. - Adds configuration for refresh-token expiration and unit/repository/controller tests for the new behavior.
Reviewed changes
Copilot reviewed 20 out of 20 changed files in this pull request and generated 3 comments.
Show a summary per file
| File | Description |
|---|---|
| src/main/kotlin/com/moa/entity/RefreshToken.kt | New entity to persist refresh token metadata (hash/family/expiry/revocation). |
| src/main/kotlin/com/moa/repository/RefreshTokenRepository.kt | Repository for hash lookup and family-wide revocation. |
| src/main/kotlin/com/moa/service/RefreshTokenService.kt | Core refresh-token issuance/rotation/revocation logic. |
| src/main/kotlin/com/moa/common/auth/RefreshTokenHasher.kt | Secure random token generation + SHA-256 hashing. |
| src/main/kotlin/com/moa/common/auth/JwtTokenProvider.kt | Adds refresh-token expiry calculation via configurable TTL. |
| src/main/kotlin/com/moa/service/AuthService.kt | Issues refresh tokens on sign-in/up; adds refresh and logout revocation behavior. |
| src/main/kotlin/com/moa/controller/AuthController.kt | Adds /api/v1/auth/refresh endpoint. |
| src/main/kotlin/com/moa/service/dto/TokenRefreshRequest.kt | DTO for refresh requests. |
| src/main/kotlin/com/moa/service/dto/TokenRefreshResponse.kt | DTO for refresh responses. |
| src/main/kotlin/com/moa/service/dto/SignInUpResponse.kt | Adds refreshToken to sign-in/up response. |
| src/main/kotlin/com/moa/service/dto/LogoutRequest.kt | Adds optional refreshToken to logout request for revocation. |
| src/main/resources/application-local.yml | Adds refresh-token expiration config key for local profile. |
| src/main/resources/application-prod.yml | Adds refresh-token expiration config key for prod profile. |
| src/test/resources/application-test.yml | Adds refresh-token expiration config key for test profile. |
| src/test/kotlin/com/moa/common/auth/RefreshTokenHasherTest.kt | Tests refresh-token generation and hashing properties. |
| src/test/kotlin/com/moa/common/auth/JwtTokenProviderRefreshTest.kt | Tests refresh expiry time calculation. |
| src/test/kotlin/com/moa/repository/RefreshTokenRepositoryTest.kt | Tests repository lookup and family revocation behavior. |
| src/test/kotlin/com/moa/service/RefreshTokenServiceTest.kt | Tests issuance/rotation/reuse-detection/revocation paths. |
| src/test/kotlin/com/moa/service/AuthServiceRefreshTest.kt | Tests AuthService integration with refresh-token issuance/rotation/logout revocation. |
| src/test/kotlin/com/moa/controller/AuthControllerTest.kt | Tests refresh endpoint wraps service result into ApiResponse. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
Comment on lines
+32
to
+34
| val current = refreshTokenRepository.findByTokenHash(hasher.hash(plainRefreshToken)) | ||
| ?: throw UnauthorizedException() | ||
|
|
Comment on lines
+47
to
+49
| current.revoke(now) | ||
| val newPlain = persist(current.memberId, current.familyId, now) | ||
| return RotationResult(memberId = current.memberId, plainRefreshToken = newPlain) |
Comment on lines
+10
to
+26
| @Entity | ||
| class RefreshToken( | ||
| @Column(nullable = false) | ||
| val memberId: Long, | ||
|
|
||
| @Column(nullable = false) | ||
| val tokenHash: String, | ||
|
|
||
| @Column(nullable = false) | ||
| val familyId: String, | ||
|
|
||
| @Column(nullable = false) | ||
| val expiresAt: LocalDateTime, | ||
|
|
||
| @Column | ||
| var revokedAt: LocalDateTime? = null, | ||
| ) : BaseEntity() { |
- bump moa-secret submodule (a7c8138 -> c3ce3b5) to include jwt refresh config - align RefreshToken repository test datetime precision with DB datetime(6)
Collaborator
Author
|
내일 할게 |
Comment on lines
+19
to
+22
| fun hash(plain: String): String { | ||
| val digest = MessageDigest.getInstance("SHA-256").digest(plain.toByteArray(Charsets.UTF_8)) | ||
| return digest.joinToString("") { "%02x".format(it) } | ||
| } |
Comment on lines
+15
to
+16
| @Column(nullable = false) | ||
| val tokenHash: String, |
Comment on lines
+10
to
+12
| @Entity | ||
| class RefreshToken( | ||
| @Column(nullable = false) |
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.
This pull request introduces a comprehensive refresh token system for authentication, enabling secure token rotation, revocation, and reuse detection. It adds new entities, services, endpoints, and configuration for managing refresh tokens, and updates the authentication flow to issue and handle refresh tokens alongside access tokens.
The most important changes are:
Refresh Token Infrastructure:
RefreshTokenentity to persist refresh token data, including hashes, family IDs, expiration, and revocation status. (RefreshToken.kt)RefreshTokenRepositoryfor querying and revoking refresh tokens, including methods to find by token hash and revoke all tokens in a family. (RefreshTokenRepository.kt)RefreshTokenHasherfor securely generating and hashing refresh tokens. (RefreshTokenHasher.kt)RefreshTokenServiceto issue, rotate, and revoke refresh tokens, with logic for reuse detection and family-wide revocation. (RefreshTokenService.kt)Authentication Flow Updates:
AuthServiceto issue refresh tokens during sign-in/up, support token rotation, and revoke tokens on logout. (AuthService.kt) [1] [2] [3] [4]SignInUpResponseandLogoutRequestDTOs to include refresh tokens. (SignInUpResponse.kt,LogoutRequest.kt) [1] [2]TokenRefreshRequest.kt,TokenRefreshResponse.kt) [1] [2]API and Controller Enhancements:
/api/v1/auth/refreshendpoint toAuthControllerfor refreshing tokens using a valid refresh token. (AuthController.kt)Configuration and Expiration Handling:
JwtTokenProviderto support configurable refresh token expiration and added a method to compute refresh token expiry. (JwtTokenProvider.kt,application-local.yml,application-prod.yml) [1] [2] [3] [4]Testing:
RefreshTokenHasherTest.kt,RefreshTokenRepositoryTest.kt,AuthControllerTest.kt,JwtTokenProviderRefreshTest.kt) [1] [2] [3] [4]