kkokkio - 프로젝트/트러블슈팅

accessToken의 만료 여부를 어떻게 확인 할 수 있을까

파란배개 2025. 6. 16. 06:35

문제 개요

오류 상황과 영향 범위 (예: 특정 코드 실행 시 발생, 특정 라이브러리 버전 호환 문제 등) 발생 배경 (예: 코드 테스트 중, 배포 중 문제 발견 등)

  • JWT 기반 인증 시스템에서 accessToken은 10분의 만료시간을 가지며, 해당 토큰은 클라이언트의 HttpOnly Cookie에 저장됨.
  • accessToken 만료 시 클라이언트 쿠키에서도 사라지게 되어, 만료 여부를 클라이언트에서 인지할 수 없음.
  • 이로 인해 서버는 accessToken이 누락된 요청에 대해 "로그인 상태가 아닙니다" 라는 응답만을 보내게 되어, 토큰 만료 사유를 구체적으로 전달하지 못함.

오류 메시지 및 원인 분석

오류 코드, 오류 메시지 포함 HTTP 상태 코드, 애플리케이션 로그, 서버 로그 등 구체적인 오류 정보 정리 및 로그 메시지를 통한 분석 제공 문제 발생 원인에 대한 심층 분석

  • 서버 응답
{
  "code": "401",
  "message": "로그인 상태가 아닙니다."
}
  • 기대 응답
{
  "code": "401",
  "message": "만료된 토큰입니다."
}
  • 로그 메시지 분석
    • 필터에서 ExpiredJwtException을 캐치하기 전에 accessToken 자체가 쿠키에서 제거되어, 해당 예외가 발생하지 않고 AuthenticationEntryPoint가 처리된다.
  • 원인
    • accessToken 쿠키의 maxAge가 JWT 토큰의 만료 시간과 동일하게 설정되어 있어, 토큰이 만료되면 브라우저가 먼저 쿠키를 제거한다. 따라서 accessToken 유무조차 확인할 수 없게 된다.

해결 및 고민 과정

처음 문제를 접했을 때 고려했던 대안들과 선택하지 않은 이유 실험적으로 적용한 방법이 실패한 사례와 그 이유 여러 해결책 중 최적의 방안을 선택한 과정

  1. token이 null 일 경우에 예외 응답을 리턴 시키는 방법
if (token == null) {
	setErrorResponse(response, HttpStatus.UNAUTHORIZED.value(), "AccessToken이 존재하지 않습니다.");
	return;
}

해당 방식을 jwt 필터에 적용하게 될 경우, 엔드 포인트 접근시 반드시 token값이 필요하게 된다는 문제가 발생하게 됨

  1. token은 null이고 refreshToken은 null이 아닐 경우 예외 응답 리턴 시키는 방법
if (token == null && refreshToken != null) {
    throw new CustomAuthException(CustomAuthException.AuthErrorType.MISSING_TOKEN);
}

해당 방식을 통해 해결하고자 하였지만, 결국 로그인&로그아웃을 통해서 refreshToken이 존재해야만 하는 문제가 여전히 남아있음

최종 해결책 및 구현

문제 해결을 위한 단계별 조치 방법과 코드 예시 (예: 특정 애노테이션 추가, 라이브러리 버전 조정, 설정 변경 등) 참고 자료 (관련 공식 문서, 개발자 커뮤니티 게시물 등)

  • 쿠키의 만료시간과 JWT 토큰의 만료시간이 동일하여 토큰 만료와 동시에 쿠키값이 사라지기 때문에 만료 여부를 확인하기 위해서 쿠키의 maxAge를 토큰 만료시간보다 더 길게 설정
  • 이 경우, 클라이언트는 만료된 accessToken을 그대로 가지고 있으며, 서버는 이 토큰을 받아 ExpiredJwtException을 통해 만료 여부를 감지하고 적절한 메시지를 반환 할 수 있게 된다.
ResponseCookie cookie = ResponseCookie.from("accessToken", token)
    .httpOnly(true)
    .secure(true)
    .path("/")
    .sameSite("None")
    .maxAge(Duration.ofMinutes(15)) // JWT보다 더 긴 쿠키 만료시간 설정
    .build();

결과 및 성능 분석

개선 후 응답 속도, DB 부하 감소 수치 등 구체적인 데이터 포함 문제 해결 전/후 성능 비교 그래프나 로그 분석 내용 포함 이슈 트래킹 및 자동화 방안 추가 (내부 개발자가 반복적인 문제 해결을 효율적으로 관리할 수 있도록 가이드 제공)

  • accessToken 만료 시, 필터 내에서 ExpiredJwtException 발생시 → 서버가 “만료된 토큰입니다.”라는 메시지를 정상적으로 반환하게 된다.
  • 프론트는 이 메시지를 토대로 자동으로 refresh 요청을 보내는 로직을 구현할 수 있게 된다.

추가 개선점

유사한 문제를 방지하기 위한 주의할 점 (예: 애노테이션 명시 여부, 프레임워크 업데이트 주기 확인 등) 문제 해결 과정에서 배운 점 및 중요한 교훈 공유 보안 고려 사항 추가 (해결 과정에서 발생할 수 있는 보안 리스크 및 예방 조치 포함)

  • 백엔드에서 토큰 재발급(Refresh)로직 연계 자동화 고려
  • 쿠키에 만료된 토큰을 남겨두는 방식이므로, 보안 민감 환경에서 엄격한 만료 관리가 필요하다.
댓글수0