에러코드와 Jwt 토큰

가온·2025년 6월 20일

백엔드 개발을 하면서 새롭게 배우고 적용하고 있던 것들 정리
무턱대고 만드는 것보다 이해하고 적용하는 게 재밌는 것 같긴 하다.
그리고 이해할 때 ai 사용하면 훨씬 빠르게 이해가 가능한 것 같다.

에러코드

1. 에러 코드란?

에러 코드는 서버에서 발생한 예외나 비정상 상황을 정형화된 숫자나 문자열로 표현한 값
이 코드는 클라이언트에게 오류의 원인을 전달하고, 자동화된 예외 처리를 가능하게 함.

2. 에러 코드 구성 원칙

  • 형식 : 5자리 숫자 권장 (ex: 10001, 20001)
  • 의미 및 구분 : 앞 23자리는 도메인(업무 영역), 뒤 23자리는 세부 오류 코드
  • HTTP 상태 코드와 분리 : 실제 HTTP 응답은 200 OK로 통일하고, 에러는 응답 본문(ApiResponse)에 포함된 에러 코드로 처리

3. 실제 에러 코드 설계 예시

에러 코드 | 메시지 설명

10001 잘못된 요청입니다. 공통 유효성 실패
10002 필수 입력 항목이 누락되었습니다. DTO의 NotBlank 등
20001 사용자를 찾을 수 없습니다. User 조회 실패
20002 이메일과 비밀번호는 필수 입력입니다. 로그인 입력 누락

4. 설정 및 적용 방식

① ErrorCode Enum 정의

@Getter
public enum ErrorCode {
    INVALID_REQUEST(10001, "잘못된 요청입니다."),
    MISSING_REQUIRED_FIELD(10002, "필수 입력 항목이 누락되었습니다."),
    USER_NOT_FOUND(20001, "사용자를 찾을 수 없습니다."),
    ...
    SERVER_ERROR(90001, "서버 내부 오류가 발생했습니다.");

    private final int code;
    private final String message;

    ErrorCode(int code, String message) {
        this.code = code;
        this.message = message;
    }
}

② ApiResponse 응답 형식

{
  "success": false,
  "data": null,
  "message": "사용자를 찾을 수 없습니다.",
  "errorCode": 20001
}

③ CustomException으로 throw

throw new CustomException(ErrorCode.USER_NOT_FOUND);

④ GlobalExceptionHandler에서 일괄 처리

@ExceptionHandler(CustomException.class)
public ResponseEntity<ApiResponse<Void>> handleCustomException(CustomException ex) {
    ErrorCode errorCode = ex.getErrorCode();
    return ResponseEntity
            .ok(ApiResponse.error(errorCode.getMessage(), errorCode.getCode()));
}

5. 장점

  • 에러 발생 위치 및 종류를 명확히 식별 가능

  • 클라이언트 자동화 처리 및 메시지 분기 처리 용이

  • 실제 HTTP 상태는 항상 200 OK, 문제는 errorCode로 표현 → 프론트엔드, 앱에서 일관된 응답 구조 확보

6. 적용 시 체크리스트

  • 에러 코드는 도메인 단위로 정리되었는가?

  • 각각의 에러 코드가 명확한 의미를 가지고 있는가?

  • 클라이언트에서 코드 기준으로 분기 처리가 가능한가?

  • 코드 충돌을 방지하기 위한 번호 체계가 잘 정의되어 있는가?

JWT 토큰(accessToken VS refreshToken)

1. accessToken vs refreshToken 차이

항목accessTokenrefreshToken
목적인증(Authorization)accessToken 재발급
수명짧음 (15분~1시간)김 (7일~30일)
저장 위치클라이언트 메모리, 로컬스토리지보통 HttpOnly 쿠키 또는 DB
보안탈취 시 위험 → 짧게 유지탈취 시 무한 발급 가능 → 안전하게 저장 필요

2. 구현 흐름 요약

  • 로그인 시
    1) accessToken 생성

2) refreshToken 생성

3) refreshToken DB에 저장

4) 둘 다 클라이언트에 전달

  • accessToken 만료 시
    1) 클라이언트가 refreshToken으로 재요청

2) 서버가 유효성 검사 후 새 accessToken 발급

3. 패키지 구조 예시

com.example.app
├── controller           ← AuthController
├── dto                  ← LoginRequestDTO, LoginResponseDTO
├── security             ← JwtProvider
├── service              ← UserService or AuthService
├── repository           ← RefreshTokenRepository
└── entity               ← RefreshToken

4. 핵심 메서드 정리

🔹 JwtProvider.java

public String generateAccessToken(User user);
public String generateRefreshToken(User user);

🔹 UserService.java or AuthService.java

public String loginUser(String email, String password); // accessToken 발급
public String generateAndStoreRefreshToken(User user);  // refreshToken 발급 + 저장

🔹 AuthController.java

@PostMapping("/login")
public ResponseEntity<?> loginUser(...) {
    accessToken = userService.loginUser(...);
    refreshToken = userService.generateAndStoreRefreshToken(...);
    return ResponseEntity.ok(new LoginResponseDTO(..., accessToken, refreshToken));
}

5. RefreshToken 저장소 (JPA 예시)

  • entity/RefreshToken.java
@Entity
public class RefreshToken {
    @Id @GeneratedValue
    private Long id;

    private Long userId;
    private String token;
    private LocalDateTime expiryDate;
}
  • repository/RefreshTokenRepository.java
public interface RefreshTokenRepository extends JpaRepository<RefreshToken, Long> {
    Optional<RefreshToken> findByToken(String token);
    void deleteByUserId(Long userId);
}

6. 토큰 재발급 API (선택)

POST /auth/refresh
→ refreshToken을 검증 후 새 accessToken 반환

0개의 댓글