From c227a0b76bc663f23afb42ae2a7cdde511dece09 Mon Sep 17 00:00:00 2001 From: nYeonG4001 <2371324@hansung.ac.kr> Date: Sun, 12 Apr 2026 11:09:47 +0900 Subject: [PATCH] =?UTF-8?q?fix:=20/auth/refresh=20=EC=9D=91=EB=8B=B5?= =?UTF-8?q?=EC=97=90=20hasSession=20=EC=BF=A0=ED=82=A4=20=EC=9E=AC?= =?UTF-8?q?=EC=84=A4=EC=A0=95=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit refresh 시 refreshToken maxAge는 갱신되지만 hasSession은 갱신되지 않아 최초 로그인 후 7일이 지나면 hasSession이 먼저 만료되고 새로고침 시 로그인이 풀리는 문제 수정 --- .../user/controller/AuthController.java | 1 + .../user/controller/AuthControllerTest.java | 30 +++++++++++++++++-- 2 files changed, 29 insertions(+), 2 deletions(-) diff --git a/src/main/java/com/devpick/domain/user/controller/AuthController.java b/src/main/java/com/devpick/domain/user/controller/AuthController.java index e7f6bec5..f5fc8ee9 100644 --- a/src/main/java/com/devpick/domain/user/controller/AuthController.java +++ b/src/main/java/com/devpick/domain/user/controller/AuthController.java @@ -109,6 +109,7 @@ public ApiResponse refresh( HttpServletResponse response) { String[] tokens = tokenService.reissueTokens(refreshToken); setRefreshTokenCookie(response, tokens[1]); + setHasSessionCookie(response); return ApiResponse.ok(new TokenResponse(tokens[0])); } diff --git a/src/test/java/com/devpick/domain/user/controller/AuthControllerTest.java b/src/test/java/com/devpick/domain/user/controller/AuthControllerTest.java index 91d41596..0caf70c5 100644 --- a/src/test/java/com/devpick/domain/user/controller/AuthControllerTest.java +++ b/src/test/java/com/devpick/domain/user/controller/AuthControllerTest.java @@ -246,7 +246,7 @@ void logout_userNotFound_returns404() throws Exception { // ── refresh ────────────────────────────────────────────── @Test - @DisplayName("POST /auth/refresh - Cookie의 Refresh Token으로 새 accessToken(바디)과 refreshToken(Cookie)을 반환한다") + @DisplayName("POST /auth/refresh - Cookie의 Refresh Token으로 새 accessToken(바디), refreshToken(Cookie), hasSession(Cookie)을 반환한다") void refresh_success() throws Exception { given(tokenService.reissueTokens("valid-refresh-token")) .willReturn(new String[]{"new-access-token", "new-refresh-token"}); @@ -258,7 +258,26 @@ void refresh_success() throws Exception { .andExpect(jsonPath("$.data.accessToken").value("new-access-token")) .andExpect(header().string("Set-Cookie", containsString("HttpOnly"))) .andExpect(header().string("Set-Cookie", containsString("SameSite=None"))) - .andExpect(header().string("Set-Cookie", containsString("refreshToken=new-refresh-token"))); + .andExpect(header().string("Set-Cookie", containsString("refreshToken=new-refresh-token"))) + .andExpect(result -> assertThat( + result.getResponse().getHeaders("Set-Cookie"), + hasItem(allOf(containsString("hasSession=true"), containsString("SameSite=Lax"))))); + } + + @Test + @DisplayName("POST /auth/refresh - 성공 시 hasSession 쿠키의 maxAge가 refreshToken과 동일하게 갱신된다") + void refresh_success_hasSessionMaxAgeRenewed() throws Exception { + given(tokenService.reissueTokens("valid-refresh-token")) + .willReturn(new String[]{"new-access-token", "new-refresh-token"}); + + mockMvc.perform(post("/auth/refresh") + .cookie(new Cookie(AuthController.REFRESH_TOKEN_COOKIE, "valid-refresh-token"))) + .andExpect(status().isOk()) + .andExpect(result -> assertThat( + result.getResponse().getHeaders("Set-Cookie"), + hasItem(allOf( + containsString("hasSession=true"), + containsString("Max-Age=" + AuthController.REFRESH_TOKEN_MAX_AGE))))); } @Test @@ -273,6 +292,13 @@ void refresh_invalidToken_returns401() throws Exception { .andExpect(jsonPath("$.success").value(false)); } + @Test + @DisplayName("POST /auth/refresh - refreshToken 쿠키가 없으면 401을 반환한다") + void refresh_missingCookie_returns401() throws Exception { + mockMvc.perform(post("/auth/refresh")) + .andExpect(status().isUnauthorized()); + } + // ── email/send & email/verify ────────────────────────────────────────────── @Test