diff --git a/src/main/java/com/eactive/apim/portal/apps/session/controller/SessionApiController.java b/src/main/java/com/eactive/apim/portal/apps/session/controller/SessionApiController.java
index 60dc7ce..c83b133 100644
--- a/src/main/java/com/eactive/apim/portal/apps/session/controller/SessionApiController.java
+++ b/src/main/java/com/eactive/apim/portal/apps/session/controller/SessionApiController.java
@@ -5,6 +5,7 @@ import com.eactive.apim.portal.apps.session.service.UserSessionService;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.http.ResponseEntity;
+import org.springframework.security.web.csrf.CsrfToken;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
@@ -25,6 +26,8 @@ import java.util.Optional;
*
GET /api/session/status - 잔여 시간/유효성 폴링 (인증 필요)
* POST /api/session/heartbeat - 세션 연장 (lastAccessTime 갱신)
* POST /api/session/check-duplicate - 로그인 전 중복 세션 확인 (CSRF 예외)
+ * GET /api/session/ping - 익명 세션 keepalive (로그인/회원가입 페이지)
+ * GET /api/session/csrf - 현재 CSRF 토큰 조회 (로그인 제출 직전 안전망)
*
*/
@Slf4j
@@ -109,6 +112,37 @@ public class SessionApiController {
return ResponseEntity.ok(result);
}
+ /**
+ * 익명(비로그인) 페이지용 세션 keepalive ping.
+ * 요청이 기존 세션에 접근하는 것만으로 컨테이너의 세션 비활성 타이머가 리셋되어
+ * 익명 세션(세션 저장 CSRF 토큰, 회원가입 본인인증 상태 포함)이 유지된다.
+ * 세션이 없으면 새로 만들지 않는다.
+ */
+ @GetMapping("/ping")
+ public ResponseEntity ping(HttpServletRequest request) {
+ request.getSession(false);
+ return ResponseEntity.noContent().build();
+ }
+
+ /**
+ * 현재 CSRF 토큰 조회 (로그인 제출 직전 안전망).
+ * 세션 만료로 토큰이 사라진 경우 CsrfFilter가 새 토큰을 생성하고,
+ * 이 핸들러가 토큰 값을 읽는 시점에 새 세션에 저장된다(LazyCsrfTokenRepository).
+ * 회원가입 절차는 세션에 본인인증 상태를 들고 있어 토큰 재발급만으로는 복구가 안 되므로
+ * 로그인 페이지 안전망으로만 사용한다.
+ */
+ @GetMapping("/csrf")
+ public ResponseEntity