[버티] 프로젝트 개발 중 마주한 사소한 이슈들

버티 프로젝트 개발 중 마주한 사소한 이슈들 정리


이 문서는 “버티” 프로젝트를 개발하면서 마주쳤던 비교적 사소하지만, 실제 구현 과정에서는 꽤나 시간을 잡아먹거나 시행착오를 유발했던 문제들을 기록해두는 공간입니다.

단순한 에러라기보다는 “한 번쯤은 헷갈릴 수 있는 포인트들”을 중심으로 정리하여, 나중에 유지보수하거나 다른 프로젝트에서 재사용할 때 참고할 수 있도록 작성합니다.


1. JJWT 라이브러리 버전에 따른 변경 사항

JJWT 라이브러리의 업데이트로 인해 토큰 생성 및 파싱 방식이 크게 변경되었습니다. 기존 방식으로 작성된 코드는 더 이상 컴파일되지 않거나 실행 시 에러가 발생할 수 있습니다.

🔧 기존 코드 (구버전 JJWT)

String secretKey = Base64.getEncoder().encodeToString(secretKey.getBytes());
Claims claims = Jwts.claims().setSubject(user.getNickname());
String accessToken = Jwts.builder()
                .setHeaderParam(Header.TYPE, Header.JWT_TYPE)
                .setClaims(claims)
                .setIssuedAt(now)
                .setExpiration(new Date(now.getTime() + ACCESS_TOKEN_VALID_MILLISECOND))
                .signWith(SignatureAlgorithm.HS256, secretKey)
                .compact();
Claims parsedClaims = Jwts.parser().setSigningKey(secretKey).parseClaimsJws(accessToken).getBody();

✅ 변경 코드 (최신 JJWT)

SecretKey secretKey = Keys.hmacShaKeyFor(secretKeyStr.getBytes());
Claims claims = Jwts.claims().subject(user.getNickname()).build();
String accessToken = Jwts.builder()
                .claims(claims)
                .header()
                .type("JWT")
                .and()
                .issuedAt(now)
                .expiration(new Date(now.getTime() + ACCESS_TOKEN_VALID_MILLISECOND))
                .signWith(secretKey, Jwts.SIG.HS256)
                .compact();
Claims parsedClaims = Jwts.parser()
                .verifyWith(secretKey)
                .build()
                .parseSignedClaims(accessToken)
                .getPayload();

참고 :


2. 카카오 소셜 로그인 이메일 누락 문제

🧩 문제 상황

카카오 로그인 시 사용자 이메일이 제공되지 않아 InternalAuthenticationServiceException 이 발생하는 문제가 있었습니다.

✅ 해결 방법

카카오 계정에 이메일 정보가 없을 경우 자동으로 생성된 이메일을 부여하도록 로직을 보완했습니다.

// KakaoOAuth2UserInfo 클래스
@Override
public String getEmail() {
    if (attributes.containsKey("kakao_account")) {
        Map<String, Object> kakaoAccount = (Map<String, Object>) attributes.get("kakao_account");
        if (kakaoAccount != null && kakaoAccount.containsKey("email")) {
            return (String) kakaoAccount.get("email");
        }
    }
    return null; // 상위 메소드에서 처리
}

// OAuth2UserService 클래스
private OAuth2User processOAuth2User(...) {
    String email = oAuth2UserInfo.getEmail();
    if (email == null || email.isEmpty()) {
        email = registrationId + "_" + oAuth2UserInfo.getId() + "@example.com";
        log.debug("이메일 정보가 없어 생성된 이메일: {}", email);
    }

    // 나머지 사용자 생성/업데이트 로직
    ...
}

3. OAuth2 인증 요청 정보 손실 문제

🧩 문제 상황

로그인 시 다음과 같은 오류가 발생했습니다:

oauth2LoginException: authorization_request_not_found

이유는 Security 설정에서 다음과 같이 세션 생성을 완전히 차단했기 때문입니다:

http.sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS);

OAuth2 로그인 과정은 내부적으로 세션에 인증 요청 정보를 저장하여 인증을 이어가는데, 해당 설정으로 인해 정보가 손실되었습니다.

✅ 해결 방법

개발 초기에는 단순화를 위해 다음과 같이 설정을 변경했습니다:

http.sessionManagement().sessionCreationPolicy(SessionCreationPolicy.IF_REQUIRED);

이를 통해 OAuth2 인증 플로우 중 세션을 사용할 수 있도록 하여 문제를 해결했습니다.

💡 추가 구현: 리프레시 토큰

보안성과 사용자 경험을 위해 리프레시 토큰도 함께 구현했습니다.

  • RefreshToken 엔티티 및 리포지토리 생성
  • 토큰 갱신 서비스 및 API 엔드포인트 구현
  • 액세스 토큰과 리프레시 토큰을 분리 관리하여 보안성 강화