목차
- 마주한 문제
- 문제 해결 과정
- 성과
- 결론
1. 마주한 문제
운영 서버의 특정 계정만 로그인 시 JWT쿠키가 생성되지 않아 로그인 실패가 발생하였다.
- 로그인 시도 시 토큰을 갱신과정에서 JWT 토큰을 쿠키에서 읽지 못함.
- 크롬/엣지 등 다른 브라우저에서도 동일 현상.
- 운영 로그를 확인해보니 로그인 시도 시 NullPointerException 발생
- 다른 OAuth 쿠키(access_token, refresh_token)는 정상 생성됨
즉, JWT 토큰 자체는 생성되는데 쿠키로 저장되지 않아 로그인 흐름이 끊어지는 문제였다.
2. 문제 해결 과정
1. NPE 발생 지점 확인
String token = CookieUtils.getCookie(request, CookieUtils.JWT_TOKEN).getValue();
- getCookie() 반환값이 null
- JWT 토큰에 쿠키를 찾지 못해 NPE 발생
2. JWT 토큰 생성은 성공 → 쿠키 저장만 실패
토큰 생성 시 상세 로그를 추가해 확인했다.
JwtTokenDto jwtToken = jwtTokenProvider.createAccessToken(username, ...);
log.debug("JWT token created for user: {}. Token length: {}", username, jwtTokenValue.length());
Cookie jwtCookie = CookieUtils.createJwtToken(jwtTokenValue);
response.addCookie(jwtCookie);
로그 결과:
JWT token created for user: test@gmail.com. Token length: 4091
JWT cookie added to response for user: test@gmail.com
- 토큰 생성 OK
- response.addCookie()도 OK
- → 그럼 왜 브라우저에 저장이 안 될까?
3. 쿠키 크기 제한 초과
브라우저 쿠키 제한
- 대부분의 브라우저는 4KB(4096 byte) 제한
문제 계정의 JWT 토큰 크기
- 토큰 길이: 4091 bytes
- 쿠키 이름 및 기타 속성: 약 60 bytes
- 총합: 약 4150 bytes → 제한 초과
→ 브라우저가 쿠키 저장을 거부한 것임!
쿠키의 크기가 4KB로 제한된 이유는 RFC 6265(HTTP State Management Mechanism) 표준에서 명시적으로 "하나의 쿠키는 최소 4,096바이트(4KB)까지 저장해야 한다"고 규정했기 때문이다.
위에 이유 때문에 모든 주요 브라우저가 쿠키를 처리할 때 호환성을 보장하기 위한 최소 요구사항으류 4KB를 맞춘다.
https://httpwg.org/specs/rfc6265.html#implementation-limits
RFC6265
HTTP State Management Mechanism
httpwg.org

4. 왜 특정 계정만 문제가 발생했는가?
해당 계정만 Member 소속 정보가 42개였다.
SELECT COUNT(*) FROM member WHERE user_id = 문제의 계정;
-- 결과: 42개
JWT 생성 로직을 보면:
List<Member> affiliatedMembers = memberService.findMembersByEmail(user.getEmail());
List<SimpleMemberDto> memberList = affiliatedMembers.stream()
.map(SimpleMemberDto::new)
.collect(Collectors.toList());
String members = toJson(memberList);
JWT Payload에 Member 리스트 전체가 포함됨
Member 개수에 따른 토큰 크기 증가
계정 타입 Member 수 JWT 크기 쿠키 저장
| 일반 | 1~5개 | ~800 bytes | 성공 |
| 문제 계정 | 42개 | 4091 bytes | 실패 |
→ Member 수가 많아질수록 JWT 크기가 동적으로 증가
→ 그 결과 브라우저 쿠키 제한을 초과
즉, 토큰 크기가 고정이 아니라, DB Member 수에 따라 가변적으로 증가하는 구조가 문제였다.
5. 해결 방안
JWT 에서 Member 상세 정보 제거
JWT에는 최소 필요 정보만 포함하도록 변경하고, Member 리스트는 API 호출로 DB조회하여 가져오도록 구조를 변경함.
- JWT 크기
- → 4091 bytes → 약 500 bytes (1/8 감소)
- 쿠키 크기 제한 안정적 확보 (Member 수와 무관)
항목 변경 전 변경 후
| JWT에 포함되는 Member 정보 | 전체 Member 리스트(가변) | 없음 |
| 토큰 크기 | 사용자별로 크게 다름 | 모든 사용자 동일하게 작아서 안정적 |
| 로그인 안정성 | Member 많은 계정은 실패 | 모든 계정 성공 |
| Member 조회 방식 | JWT 파싱 | 별도 API 호출 + DB 조회 |
3. 성과
- 문제 계정 로그인 정상화
- JWT 쿠키 미생성 및 NPE 문제 해결
- 토큰 구조 표준화 및 안정성 확보
- Member 수 증가에 따른 가변적인 JWT 크기 문제 해결
- 상세 로깅으로 재발 시 문제 추적 용이
4. 결론
- 브라우저 쿠키에는 4KB 제한이 있다.
- 토큰에 동적으로 증가하는 데이터(Member 리스트 등)를 넣으면 위험하다.
- JWT는 최소 정보만 담고, 나머지는 API + DB 조회를 통해 관리하는 것이 정상적인 아키텍처이다.
- 토큰 크기 안정화는 시스템 안정성에 매우 중요하다.
'Spring' 카테고리의 다른 글
| DTO는 어느 레이어까지 사용하는 것이 좋을까? (0) | 2024.12.29 |
|---|---|
| JPA를 사용하는 이유가 무엇일까? (0) | 2024.08.07 |
| 트랜잭션 전파 옵션을 이용해서 복구하기 (0) | 2024.08.03 |
| 스프링 트랜잭션 전파에 대해 알아보자 (0) | 2024.07.28 |
| @Transactional을 사용할때 어떤 점을 주의할까? (0) | 2024.07.11 |