DOCS/journey/troubleshooting/2025-12-04_프론트엔드_JWT_401_403_UX처리_부족.md
happybell80 bcf6d3e0dc docs: JWT 401/403 에러 UX 처리 부족 트러블슈팅
- 이고은 사용자 케이스에서 발견
- JWT 만료 시 자동 로그아웃 구현 완료 (6aa8fa4)
- 웹 테스트 완료
2025-12-04 16:52:41 +09:00

2.9 KiB

프론트엔드 JWT 401/403 에러 UX 처리 부족

날짜: 2025-12-04 작성자: Agent 관련 파일:

  • frontend-customer/src/contexts/auth-context.tsx:29-69
  • frontend-customer/src/services/robeing-api.ts

문제 상황

이고은 사용자 케이스에서 발견:

  • JWT 만료 시 모든 API 호출 401 에러
  • 프론트엔드는 로그인 상태로 표시되나 기능 사용 불가
  • 에러 메시지만 보고 원인 파악 어려움

게이트웨이 로그:

INFO: 172.21.0.1:56062 - "POST /api/chat HTTP/1.0" 401 Unauthorized
INFO: 172.21.0.1:36836 - "GET /api/preferences/... HTTP/1.0" 401 Unauthorized

원인 분석

JWT 만료 시 자동 로그아웃 없음

  • auth-context.tsx:29-69 checkAuthStatus()에서 exp 검증 없음
  • localStorage에 만료된 토큰이 남아있어도 계속 사용 시도
  • 사용자는 로그인된 것처럼 보이나 모든 API 실패

401/403 에러 처리 일관성 부족

  • API 함수마다 에러 처리 제각각
  • 401 (인증 만료) vs 403 (권한 없음) 구분 없음
  • 사용자에게 명확한 안내 없음

해결 방안

1. useApiError 훅 생성

파일: frontend-customer/src/hooks/useApiError.ts (신규)

  • 401: 토스트("로그인이 만료되었습니다") + localStorage 정리 + 리다이렉트
  • 403: 토스트("접근 권한이 없습니다")만 표시

2. auth-context JWT exp 검증

파일: frontend-customer/src/contexts/auth-context.tsx:29-69

  • checkAuthStatus()에서 payload.exp * 1000 < Date.now() 체크
  • 만료 시 localStorage 정리 + setUser(null)

3. API 에러 처리 통일

파일: frontend-customer/src/services/robeing-api.ts

  • 모든 API 함수에서 401/403 시 RobeingAPIError 던지기
  • 컴포넌트에서 useApiError로 일관 처리

HTTP 상태 코드 처리 규칙

코드 UX 처리 로그아웃
401 토스트 + 즉시 리다이렉트 Yes
403 토스트만 표시 No

구현 완료

커밋: 6aa8fa4 (2025-12-04 16:47)

변경 파일:

  • src/hooks/useApiError.ts: 신규 생성
  • src/contexts/auth-context.tsx:40-48: JWT exp 검증 추가
  • src/components/chat-interface.tsx:594-599: useApiError 적용

테스트 결과:

  • 로그인/로그아웃 정상 작동
  • 비로그인 상태 메시지 전송 시 로그인 다이얼로그 오픈
  • JWT 만료 시나리오는 시간 경과 후 재검증 필요

교훈

원칙 위반

  • React 구조 원칙 9번: 에러 처리 일관성 부족
  • React 구조 원칙 10번: 백엔드 응답 검증 부족

예방책

  • JWT 발급 시 exp 필드 필수 검증
  • API 에러는 커스텀 훅으로 중앙화
  • 401/403 구분하여 명확한 사용자 안내

향후 개선

장기: Refresh Token 구조 (Access 15분, Refresh 7일)

참고

  • React 원칙: DOCS/book/300_architecture/313_React_구조_원칙.md:131-148
  • 게이트웨이 인증: robeing-gateway/app/core/auth.py:14-51