Skip to content

[FEAT] 스프링 인증/인가 개발#32

Merged
Be-HinD merged 12 commits intomainfrom
feat/auth
Dec 7, 2025
Merged

[FEAT] 스프링 인증/인가 개발#32
Be-HinD merged 12 commits intomainfrom
feat/auth

Conversation

@Be-HinD
Copy link
Member

@Be-HinD Be-HinD commented Dec 7, 2025

📝 Pull Request

📌 PR 종류

해당하는 항목에 체크해주세요.

  • 기능 추가 (Feature)
  • 버그 수정 (Fix)
  • 문서 수정 (Docs)
  • 코드 리팩터링 (Refactor)
  • 테스트 추가 (Test)
  • 기타 변경 (Chore)

✨ 변경 내용

Spring Security + JWT 관련 설정 및 로직 개발
Auth 도메인 개발(로그인, 회원가입)
User 도메인 개발(Entity, 테스트 컨트롤러)


🔍 관련 이슈

해당 PR이 해결하는 이슈가 있다면 연결해주세요.
Closes #31


🧪 테스트

변경된 기능에 대한 테스트 범위 또는 테스트 결과를 작성해주세요.

  • 유닛 테스트 추가 / 수정
  • 통합 테스트 검증
  • 수동 테스트 완료

1. 스프링부트 로딩시점 설정 로깅

image

2. 보호된 API 요청 시 (토큰 x)

image

3. 회원가입

image

4. 로그인

image

🚨 확인해야 할 사항 (Checklist)

PR을 제출하기 전에 아래 항목들을 확인해주세요.

  • 코드 포매팅 완료
  • 불필요한 파일/코드 제거
  • 로직 검증 완료
  • 프로젝트 빌드 성공
  • 린트/정적 분석 통과 (해당 시)

🙋 기타 참고 사항

TO-DO

  1. 커스텀 예외 처리 적용
  2. 공통 응답 적용
  3. CORS 설정 추가

Summary by CodeRabbit

  • 새로운 기능

    • 회원가입·로그인·로그아웃·토큰 리프레시 API 추가 및 리프레시 토큰 쿠키 지원
    • JWT 기반 액세스/리프레시 토큰 발급 및 요청 인증 적용
  • 개선 사항

    • 역할 기반 접근 제어와 보안 설정(비밀번호 암호화 포함) 적용
    • JPA 감사(createdAt/updatedAt) 활성화 및 애플리케이션 시작 시 상세 환경/DB 로그 추가
  • 테스트

    • 인증 플로우 검증용 HTTP 테스트 컬렉션 추가
  • 기타(Chore)

    • 로컬 설정용 .gitignore 항목 및 개발용 DB(H2) 의존성 추가

✏️ Tip: You can customize this high-level summary in your review settings.

@Be-HinD Be-HinD self-assigned this Dec 7, 2025
@Be-HinD Be-HinD added the ✨enhancement New feature or request label Dec 7, 2025
@coderabbitai
Copy link

coderabbitai bot commented Dec 7, 2025

Walkthrough

Spring Security와 JWT 기반 인증 인프라(토큰 생성/검증·필터·설정), 회원가입·로그인·토큰 리프레시 API 및 사용자 도메인(JPA 엔티티·리포지토리), JPA 감사·애플리케이션 시작 로깅과 관련 빌드·설정(의존성·프로퍼티·.gitignore) 항목이 추가되었습니다.

Changes

응집(Cohort) / 파일(s) 변경 요약
보안 설정 및 JWT 인프라
src/main/java/team/wego/wegobackend/common/security/SecurityConfig.java, src/main/java/team/wego/wegobackend/common/security/jwt/JwtTokenProvider.java, src/main/java/team/wego/wegobackend/common/security/JwtAuthenticationFilter.java, src/main/java/team/wego/wegobackend/common/security/CustomUserDetailsService.java, src/main/java/team/wego/wegobackend/common/security/Role.java, src/main/java/team/wego/wegobackend/common/security/SecurityEndpoints.java
BCryptPasswordEncoder 빈 추가, SecurityFilterChain 구성(무상태·CSRF 비활성화·필터 삽입), JWT 발급/검증 API·유효성 검사, 인증 필터로 SecurityContext 설정, UserDetailsService 구현, Role enum 및 공개 엔드포인트 패턴 추가.
인증 도메인 (서비스 · 컨트롤러 · DTO)
src/main/java/team/wego/wegobackend/auth/application/AuthService.java, src/main/java/team/wego/wegobackend/auth/presentation/AuthController.java, src/main/java/team/wego/wegobackend/auth/application/dto/request/SignupRequest.java, .../LoginRequest.java, .../response/SignupResponse.java, .../response/LoginResponse.java, .../response/RefreshResponse.java
회원가입(Signup) 로직(이메일 중복 검사·BCrypt 암호화·ROLE_USER), 로그인(Login) 로직(비밀번호 검증·액세스·리프레시 토큰 발급), 리프레시로 액세스 재발급, 관련 요청/응답 DTO와 컨트롤러 엔드포인트(리프레시 토큰을 HttpOnly Secure 쿠키로 설정 포함).
사용자 도메인 (엔티티 · 리포지토리 · DTO · 컨트롤러)
src/main/java/team/wego/wegobackend/user/domain/User.java, src/main/java/team/wego/wegobackend/user/repository/UserRepository.java, src/main/java/team/wego/wegobackend/user/application/dto/response/UserInfoResponse.java, src/main/java/team/wego/wegobackend/user/presentation/UserController.java
JPA User 엔티티(BaseTimeEntity 상속, 필드·제약·빌더), 이메일 조회/존재 검사 리포지토리, UserInfoResponse DTO, 간단한 테스트 엔드포인트 추가.
공통 인프라 및 시작 로그
src/main/java/team/wego/wegobackend/common/entity/BaseTimeEntity.java, src/main/java/team/wego/wegobackend/common/config/ApplicationStartupLogger.java, src/main/java/team/wego/wegobackend/WegobackendApplication.java
JPA Auditing용 BaseTimeEntity 추가 및 @EnableJpaAuditing 활성화, 애플리케이션 시작 시 환경·DB·JPA·JWT·서버 정보 로깅 컴포넌트 추가.
빌드 · 설정 · 기타
build.gradle, src/main/resources/application.yml, .gitignore, src/test/http/auth/auth-api.http
JWT·Spring Security·H2 의존성 추가, application.yml에 로컬 프로필·JWT 설정 변경 및 ddl-auto 조정, 로컬 프로파일 파일(/src/main/resources/application-local.yml)을 .gitignore에 추가, 인증 흐름을 검증하는 HTTP 테스트 컬렉션 추가.

Sequence Diagram(s)

sequenceDiagram
    participant Client
    participant AuthCtrl as AuthController
    participant AuthSvc as AuthService
    participant UserRepo as UserRepository
    participant BCrypt as BCryptPasswordEncoder
    participant JwtProv as JwtTokenProvider
    participant Response

    Client->>AuthCtrl: POST /api/v1/auth/login (email,password)
    AuthCtrl->>AuthSvc: login(request)
    AuthSvc->>UserRepo: findByEmail(email)
    alt 사용자 없음
        AuthSvc-->>AuthCtrl: 예외(사용자 없음)
    else 사용자 존재
        AuthSvc->>BCrypt: matches(plain, encoded)
        alt 비밀번호 불일치
            AuthSvc-->>AuthCtrl: 예외(비밀번호 불일치)
        else 인증 성공
            AuthSvc->>JwtProv: createAccessToken(email, role)
            JwtProv-->>AuthSvc: accessToken
            AuthSvc->>JwtProv: createRefreshToken(email)
            JwtProv-->>AuthSvc: refreshToken
            AuthSvc->>JwtProv: getAccessTokenExpiresIn()
            JwtProv-->>AuthSvc: expiresIn
            AuthSvc-->>AuthCtrl: LoginResponse(accessToken, refreshToken, expiresIn)
        end
    end
    AuthCtrl->>Response: 200 OK + accessToken, set HttpOnly Secure refresh cookie
    Response-->>Client: tokens + user info
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~45 minutes

  • 주의 깊게 검토할 항목:
    • JwtTokenProvider: 시크릿/키 초기화, 토큰 타입(claim) 일관성 및 예외 처리
    • SecurityConfig / JwtAuthenticationFilter: 필터 체인 순서, SecurityContext 설정 안정성
    • AuthController/AuthService: 리프레시 토큰을 쿠키로 설정/삭제하는 속성(경로·SameSite·Secure·HttpOnly)과 트랜잭션 범위
    • User 엔티티/리포지토리: 컬럼 제약(유니크 등) 및 BaseTimeEntity 연동
    • ApplicationStartupLogger: 민감 정보 마스킹 및 DB 연결 예외 처리

Poem

🐇 토끼가 쓴 축하 시
당근처럼 반짝이는 토큰 한 쌈 🥕
필터 숲을 지나 안전히 달리고
쿠키 품에 숨은 리프레시 한 점
로그 불빛 속 서비스가 깨어나 ✨

Pre-merge checks and finishing touches

❌ Failed checks (1 warning)
Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 28.57% which is insufficient. The required threshold is 80.00%. You can run @coderabbitai generate docstrings to improve docstring coverage.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed PR 제목이 주요 변경사항을 명확히 요약하고 있습니다. '[FEAT] 스프링 인증/인가 개발'은 Spring Security와 JWT를 기반으로 한 인증/인가 기능 개발이 핵심 변경사항임을 잘 나타냅니다.
Linked Issues check ✅ Passed PR의 모든 코드 변경사항이 연결된 이슈 #31의 세 가지 요구사항을 충족합니다: ① Security Config와 JWT 인증 로직 (SecurityConfig, JwtTokenProvider, JwtAuthenticationFilter), ② User 도메인 (User 엔티티, UserRepository, UserController), ③ Auth 도메인 (회원가입, 로그인 로직)이 모두 구현되었습니다.
Out of Scope Changes check ✅ Passed 모든 변경사항이 인증/인가 기능 구현 범위 내에 있습니다. .gitignore 추가, 의존성 설정, 설정 파일, 로깅 기능은 모두 인증/인가 기능을 지원하는 필수 설정입니다.
✨ Finishing touches
  • 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch feat/auth

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 5

🧹 Nitpick comments (17)
.gitignore (1)

750-751: 로컬 프로파일 설정 파일 ignore 방향 좋습니다

application-local.yml을 Git에서 제외해 두신 건 로컬용 DB/JWT 설정 등 민감한 값을 보호하는 데 적절합니다. 필요하다면 팀원 온보딩을 위해 application-local.example.yml 같은 샘플 파일을 별도로 두는 것도 고려해 보셔도 좋겠습니다.

build.gradle (1)

39-45: Security / JWT / H2 의존성 추가 방향은 타당하지만 좌표 확인을 권장합니다

  • spring-boot-starter-security, spring-security-test 추가는 이번 PR의 인증/인가 구현과 잘 맞습니다.
  • io.jsonwebtoken:jjwt:0.12.6는 버전과 모듈 구성이 종종 바뀌는 라이브러리라, 현재 사용 중인 예제/공식 문서 기준으로 단일 jjwt 아티팩트만으로 충분한지(또는 jjwt-api, jjwt-impl, jjwt-jackson 등 별도 모듈이 필요한지) 한 번만 더 확인해 주세요.
  • com.h2database:h2runtimeOnly로 두면 운영 classpath에도 포함됩니다. 실제 운영에서는 MySQL만 쓰고 H2는 로컬/테스트 전용이라면, 프로파일별 설정이나 test 전용 스코프(testRuntimeOnly)로 한정하는 것도 고려해 볼 수 있습니다.

현재 Spring Boot / JJWT 최신 문서를 한 번 검색해서, 이 버전 조합에서 권장하는 의존성 구성이 무엇인지 재확인해 주세요.

src/main/java/team/wego/wegobackend/auth/application/dto/request/LoginRequest.java (1)

1-17: 로그인 요청 DTO 설계 무난합니다

이메일/비밀번호에 대한 @Email, @NotBlank 조합과 한글 메시지가 회원가입 DTO와 일관적이라, 현재 요구사항 기준으로는 충분해 보입니다. 이후 비밀번호 정책이 정해지면 @Size@Pattern을 추가하는 정도만 고려하시면 될 것 같습니다.

src/main/java/team/wego/wegobackend/auth/application/dto/request/SignupRequest.java (1)

13-25: 회원가입 DTO 유효성 정의 일관적이며, 닉네임 메시지 문구만 소소한 보완 여지

  • 이메일/비밀번호/닉네임/전화번호에 대한 제약과 한글 메시지가 잘 정의되어 있고, 로그인 DTO와도 일관성이 있습니다.
  • 다만 nickName 필드에 "이름은 필수입니다"라는 메시지를 사용하고 있어, 실제 UI에서는 "닉네임은 필수입니다"처럼 필드명과 용어를 맞춰 주면 사용자가 헷갈지 않을 것 같습니다.
src/main/java/team/wego/wegobackend/common/config/ApplicationStartupLogger.java (1)

139-142: maskPassword에서 URL null 처리로 방어적 코드를 추가하면 좋습니다

일부 DataSource 구현에서 metaData.getURL()null을 반환할 수도 있어, 현재 구현은 이 경우 NPE가 발생합니다(물론 상위에서 catch 하고 있긴 합니다). 아래처럼 간단한 null 처리를 추가하면 로그 실패 자체도 방지할 수 있습니다.

-    private String maskPassword(String url) {
-        // URL에서 비밀번호 마스킹
-        return url.replaceAll("password=[^&;]+", "password=****");
-    }
+    private String maskPassword(String url) {
+        if (url == null) {
+            return null;
+        }
+        // URL에서 비밀번호 마스킹
+        return url.replaceAll("password=[^&;]+", "password=****");
+    }
src/main/resources/application.yml (1)

5-7: 프로파일/DDL/JWT 설정 전반은 합리적이나, 활성 프로파일 하드코딩은 한 번 더 검토를 권장합니다

  • spring.jpa.hibernate.ddl-auto: none으로 바꾸신 것은 운영/공용 DB에서 스키마를 임의로 생성/드롭하지 않도록 막는 측면에서 좋은 선택입니다(마이그레이션 도구나 별도 스크립트와 함께 사용 가정으로 보입니다).
  • jwt.secret과 access/refresh 토큰 만료 설정 구조(jwt.access.token.expiration, jwt.refresh.token.expiration)도 분리도가 좋고, ApplicationStartupLogger에서 이 키들을 사용하도록만 맞춰 주시면 일관성이 유지됩니다(별도 코멘트에서 제안드린 대로).
  • 다만 application.ymlspring.profiles.active: local을 직접 넣어 두면, 별도 환경 변수/옵션으로 덮어쓰지 않는 한 모든 환경에서 local 프로파일이 기본 활성됩니다. 실제 배포 환경에서 prod/stage 등의 프로파일을 사용할 계획이라면:
    • 배포 환경에서 SPRING_PROFILES_ACTIVE로 항상 덮어쓰거나,
    • 또는 application-local.yml에만 spring.config.activate.on-profile: local 형태로 로컬 전용 설정을 두고, 기본 application.yml에는 active를 비워 두는 방식을 고려해 보셔도 좋겠습니다.

배포 방식에 따라 현재 spring.profiles.active 설정이 의도한 대로 동작하는지(예: Docker/K8s에서 env로 항상 override하는지) 한 번만 더 확인해 주세요.

Also applies to: 37-37, 81-90

src/main/java/team/wego/wegobackend/auth/application/dto/response/SignupResponse.java (1)

19-27: PII 노출 검토 필요

회원가입 응답에 email, phoneNumber 같은 민감한 개인정보(PII)가 포함되어 있습니다. 이 정보가 클라이언트에 반드시 필요한지 검토해 주세요. 특히 phoneNumber는 회원가입 확인 응답에서 반환할 필요가 없을 수 있습니다.

최소 권한 원칙에 따라 필요한 정보만 반환하는 것을 권장합니다.

src/main/java/team/wego/wegobackend/user/presentation/UserController.java (2)

9-13: 사용되지 않는 어노테이션 정리

@Slf4j@RequiredArgsConstructor 어노테이션이 선언되어 있지만 현재 사용되지 않습니다. 테스트 목적의 임시 컨트롤러라면 불필요한 어노테이션을 제거하거나, 향후 기능 확장 시 필요하다면 그대로 유지해도 됩니다.


15-19: 테스트 엔드포인트 명시 필요

이 엔드포인트가 인증/인가 테스트 목적이라면 주석이나 TODO로 명시하여 프로덕션 배포 전 제거 또는 비활성화가 필요함을 표시하는 것이 좋습니다.

+    // TODO: 테스트용 엔드포인트 - 프로덕션 배포 전 제거 필요
     @GetMapping("/test")
     public String test() {
-
         return "test Success";
     }
src/main/java/team/wego/wegobackend/common/security/SecurityConfig.java (1)

55-55: CORS 설정 추가 필요

PR 목표에 명시된 대로 CORS 설정이 필요합니다. 프론트엔드와의 통합 전에 반드시 구현되어야 합니다.

CORS 설정 구현을 도와드릴까요?

src/main/java/team/wego/wegobackend/common/security/CustomUserDetailsService.java (1)

21-24: 예외 메시지에서 이메일 노출 주의

예외 메시지에 사용자 이메일이 포함되어 있습니다. 이 정보가 로그에 기록될 경우 민감한 정보가 노출될 수 있습니다.

         User user = userRepository.findByEmail(email)
-            .orElseThrow(() -> new UsernameNotFoundException("사용자를 찾을 수 없습니다: " + email));
+            .orElseThrow(() -> new UsernameNotFoundException("사용자를 찾을 수 없습니다"));

로깅이 필요한 경우 별도로 마스킹 처리하여 기록하는 것을 권장합니다.

src/main/java/team/wego/wegobackend/auth/presentation/AuthController.java (1)

17-44: AuthController 설계는 깔끔하며 현재 요구사항을 잘 충족합니다

  • 엔드포인트 URL, HTTP 메서드, @Valid @RequestBody 적용 등 전반적인 구성은 무난합니다.
  • 향후 PR 설명에 있는 “공통 응답 / 커스텀 예외 처리”가 도입되면, 컨트롤러에서도 ResponseEntity.ok(...) 대신 공통 응답 포맷을 반환하도록 맞춰주는 정도만 추가로 고려하시면 될 것 같습니다.
  • @Slf4j를 이미 붙이셨으니, 로그인/회원가입 성공·실패 시 간단한 로그 정도만 남겨 두면 추후 운영 시 추적에 도움이 될 것 같습니다.
src/main/java/team/wego/wegobackend/common/security/SecurityEndpoints.java (1)

3-10: 유틸리티 클래스는 인스턴스화 불가하게 막아두면 좋습니다

SecurityEndpoints는 상수만 가지고 있어 인스턴스화될 필요가 없어 보입니다. final 클래스 + private 생성자를 두면 의도를 더 명확히 할 수 있습니다.

-public class SecurityEndpoints {
-
-    public static final String[] PUBLIC_PATTERNS = {
-        "/api/v*/auth/**",
-        "/api/v*/docs/**",
-        "/api/v*/health",
-        "/error"
-    };
-}
+public final class SecurityEndpoints {
+
+    private SecurityEndpoints() {
+        throw new AssertionError("Cannot instantiate utility class");
+    }
+
+    public static final String[] PUBLIC_PATTERNS = {
+        "/api/v*/auth/**",
+        "/api/v*/docs/**",
+        "/api/v*/health",
+        "/error"
+    };
+}
src/main/java/team/wego/wegobackend/user/domain/User.java (1)

55-68: Boolean 래퍼 대신 primitive boolean 사용을 검토해 주세요

  • notification_enabled, is_deleted 컬럼이 nullable = false인데, 자바 타입은 Boolean(래퍼)라 이론상 null이 들어갈 여지가 있습니다.
  • 현재는 필드 초기값을 false로 주고 있어 실질적인 문제는 없지만, 도메인 의미상 “반드시 true/false 둘 중 하나”여야 하므로 primitive boolean으로 두는 편이 더 안전합니다.

예시:

-    @Column(name = "notification_enabled", nullable = false)
-    private Boolean notificationEnabled = false;
+    @Column(name = "notification_enabled", nullable = false)
+    private boolean notificationEnabled = false;
@@
-    @Column(name = "is_deleted", nullable = false)
-    private Boolean deleted = false;
+    @Column(name = "is_deleted", nullable = false)
+    private boolean deleted = false;
src/main/java/team/wego/wegobackend/auth/application/dto/response/LoginResponse.java (1)

18-42: LoginResponse 구성은 일관적이며 사용성도 좋습니다 (만료 시간 표현 관련 소소한 제안)

  • 액세스/리프레시 토큰, tokenType = "Bearer", expiresIn, user 포함 구조가 직관적이고, 정적 팩토리 메서드 패턴도 잘 맞습니다.
  • expiresAtLocalDateTime.now().plusSeconds(expiresIn)으로 계산하는 것도 실사용에는 충분하지만, 추후 타임존 이슈나 서버 간 시간 차이를 더 엄밀히 다루고 싶다면 Instant 혹은 OffsetDateTime 기반으로 표현하는 것도 한 번 고민해 볼 만합니다.
src/main/java/team/wego/wegobackend/auth/application/AuthService.java (1)

29-75: 회원가입/로그인 핵심 로직은 요구사항을 잘 충족하며, 예외/중복 처리에서 몇 가지 다듬을 부분이 있습니다

  • 회원가입에서 이메일 중복은 사전 체크하고 있지만 닉네임은 DB unique 제약에만 의존하는 구조라, 중복 시에는 현재로서는 다소 애매한 서버 에러가 나갈 수 있습니다. 추후 커스텀 예외/공통 응답을 붙이실 때 닉네임 중복도 도메인 예외로 변환해 주면 사용자 경험이 더 좋아질 것 같습니다.
  • 로그인에서 “존재하지 않는 사용자”와 “잘못된 비밀번호”를 구분해 주는 것은 친절하지만, 계정 존재 여부를 유추할 수 있어 보안 측면에서는 약점이 될 수 있습니다. 나중에 예외 계층을 정리하실 때 두 경우를 동일한 메시지/응답 코드(예: “이메일 또는 비밀번호가 올바르지 않습니다”)로 합치는 것도 고려해 보시면 좋겠습니다.
  • 그 외 비즈니스 플로우(패스워드 인코딩, 삭제 계정 차단, JWT 발급 및 만료시간 계산)는 현재 PR 범위 내에서는 자연스럽게 잘 구성되어 있습니다.
src/main/java/team/wego/wegobackend/common/security/jwt/JwtTokenProvider.java (1)

21-35: JWT 시크릿 초기화 시 설정 검증을 명시적으로 추가하는 것을 권장합니다.

secretKeyStringnull 이거나 공백이거나 Base64 형식이 아니면 Decoders.BASE64.decode(secretKeyString) 에서 애매한 예외로 애플리케이션이 부팅 중 실패합니다. 지금처럼 fail-fast 하는 방향은 좋지만, 설정 누락/오타에 대해 더 명확한 메시지로 IllegalStateException 을 던지면 운영 중 트러블슈팅이 훨씬 수월할 것 같습니다.

또한 ApplicationStartupLogger.logJwtSettings() 에서는 jwt.expiration 값을 로그로 출력하는데, 이 클래스는 jwt.access.token.expiration, jwt.refresh.token.expiration 을 사용 중이라 설정 키가 서로 달라 혼동을 줄 수 있습니다. 가능하다면 하나의 규칙으로 통일하거나, 로그 쪽도 access/refresh 각각을 출력하도록 맞추는 것을 고려해 주세요.

예시:

@PostConstruct
protected void init() {
-    this.secretKey = Keys.hmacShaKeyFor(Decoders.BASE64.decode(secretKeyString));
+    if (secretKeyString == null || secretKeyString.isBlank()) {
+        throw new IllegalStateException("jwt.secret 가 설정되어 있지 않습니다.");
+    }
+
+    this.secretKey = Keys.hmacShaKeyFor(Decoders.BASE64.decode(secretKeyString));
}
📜 Review details

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between ea5bea9 and f476cd0.

📒 Files selected for processing (23)
  • .gitignore (1 hunks)
  • build.gradle (1 hunks)
  • src/main/java/team/wego/wegobackend/WegobackendApplication.java (1 hunks)
  • src/main/java/team/wego/wegobackend/auth/application/AuthService.java (1 hunks)
  • src/main/java/team/wego/wegobackend/auth/application/dto/request/LoginRequest.java (1 hunks)
  • src/main/java/team/wego/wegobackend/auth/application/dto/request/SignupRequest.java (1 hunks)
  • src/main/java/team/wego/wegobackend/auth/application/dto/response/LoginResponse.java (1 hunks)
  • src/main/java/team/wego/wegobackend/auth/application/dto/response/SignupResponse.java (1 hunks)
  • src/main/java/team/wego/wegobackend/auth/presentation/AuthController.java (1 hunks)
  • src/main/java/team/wego/wegobackend/common/config/ApplicationStartupLogger.java (1 hunks)
  • src/main/java/team/wego/wegobackend/common/entity/BaseTimeEntity.java (1 hunks)
  • src/main/java/team/wego/wegobackend/common/security/CustomUserDetailsService.java (1 hunks)
  • src/main/java/team/wego/wegobackend/common/security/JwtAuthenticationFilter.java (1 hunks)
  • src/main/java/team/wego/wegobackend/common/security/Role.java (1 hunks)
  • src/main/java/team/wego/wegobackend/common/security/SecurityConfig.java (1 hunks)
  • src/main/java/team/wego/wegobackend/common/security/SecurityEndpoints.java (1 hunks)
  • src/main/java/team/wego/wegobackend/common/security/jwt/JwtTokenProvider.java (1 hunks)
  • src/main/java/team/wego/wegobackend/user/application/dto/response/UserInfoResponse.java (1 hunks)
  • src/main/java/team/wego/wegobackend/user/domain/User.java (1 hunks)
  • src/main/java/team/wego/wegobackend/user/presentation/UserController.java (1 hunks)
  • src/main/java/team/wego/wegobackend/user/repository/UserRepository.java (1 hunks)
  • src/main/resources/application.yml (3 hunks)
  • src/test/http/auth/auth-api.http (1 hunks)
🧰 Additional context used
🧬 Code graph analysis (10)
src/main/java/team/wego/wegobackend/user/presentation/UserController.java (1)
src/main/java/team/wego/wegobackend/image/presentation/ImageController.java (1)
  • RestController (17-94)
src/main/java/team/wego/wegobackend/auth/application/dto/request/LoginRequest.java (3)
src/main/java/team/wego/wegobackend/auth/application/dto/request/SignupRequest.java (1)
  • Getter (9-26)
src/main/java/team/wego/wegobackend/auth/application/dto/response/LoginResponse.java (1)
  • Getter (13-43)
src/main/java/team/wego/wegobackend/auth/application/dto/response/SignupResponse.java (1)
  • Getter (12-38)
src/main/java/team/wego/wegobackend/auth/application/dto/response/SignupResponse.java (3)
src/main/java/team/wego/wegobackend/auth/application/dto/request/LoginRequest.java (1)
  • Getter (8-18)
src/main/java/team/wego/wegobackend/auth/application/dto/request/SignupRequest.java (1)
  • Getter (9-26)
src/main/java/team/wego/wegobackend/auth/application/dto/response/LoginResponse.java (1)
  • Getter (13-43)
src/main/java/team/wego/wegobackend/user/domain/User.java (1)
src/main/java/team/wego/wegobackend/user/application/dto/response/UserInfoResponse.java (1)
  • Getter (12-55)
src/main/java/team/wego/wegobackend/common/security/jwt/JwtTokenProvider.java (2)
src/main/java/team/wego/wegobackend/common/security/JwtAuthenticationFilter.java (1)
  • Slf4j (19-67)
src/main/java/team/wego/wegobackend/common/config/ApplicationStartupLogger.java (1)
  • Component (14-143)
src/main/java/team/wego/wegobackend/auth/presentation/AuthController.java (1)
src/main/java/team/wego/wegobackend/auth/application/AuthService.java (1)
  • Slf4j (17-76)
src/main/java/team/wego/wegobackend/common/security/JwtAuthenticationFilter.java (1)
src/main/java/team/wego/wegobackend/common/security/jwt/JwtTokenProvider.java (1)
  • Slf4j (17-109)
src/main/java/team/wego/wegobackend/auth/application/dto/response/LoginResponse.java (3)
src/main/java/team/wego/wegobackend/auth/application/dto/request/LoginRequest.java (1)
  • Getter (8-18)
src/main/java/team/wego/wegobackend/auth/application/dto/request/SignupRequest.java (1)
  • Getter (9-26)
src/main/java/team/wego/wegobackend/auth/application/dto/response/SignupResponse.java (1)
  • Getter (12-38)
src/main/java/team/wego/wegobackend/auth/application/dto/request/SignupRequest.java (1)
src/main/java/team/wego/wegobackend/auth/application/dto/request/LoginRequest.java (1)
  • Getter (8-18)
src/main/java/team/wego/wegobackend/common/security/SecurityConfig.java (1)
src/main/java/team/wego/wegobackend/common/security/SecurityEndpoints.java (1)
  • SecurityEndpoints (3-11)
🔇 Additional comments (10)
src/main/java/team/wego/wegobackend/WegobackendApplication.java (1)

5-8: JPA Auditing 활성화 구성 적절합니다

@EnableJpaAuditing을 메인 애플리케이션에 추가한 방향이 BaseTimeEntity 기반 생성/수정일 관리와 잘 맞습니다. 현재 구조에서는 이 위치에 두셔도 무방해 보입니다.

src/main/java/team/wego/wegobackend/common/security/Role.java (1)

1-6: 역할 Enum 정의가 Spring Security 컨벤션과 잘 맞습니다

ROLE_USER, ROLE_ADMIN처럼 ROLE_ 프리픽스를 포함한 Enum 설계는 SimpleGrantedAuthority(user.getRole().name()) 패턴과 잘 호환되고, 이후 역할 확장도 용이해 보입니다.

src/main/java/team/wego/wegobackend/auth/application/dto/response/SignupResponse.java (1)

29-37: LGTM!

정적 팩토리 메서드 패턴이 잘 적용되어 있으며, LoginResponse와 일관된 구조를 유지하고 있습니다.

src/test/http/auth/auth-api.http (1)

1-27: LGTM! 인증 플로우 테스트가 잘 구성되어 있습니다.

회원가입 → 로그인 → 토큰 추출 → 보호된 API 호출의 전체 플로우가 잘 작성되어 있습니다. 추후 에러 케이스(잘못된 자격 증명, 중복 이메일, 만료된 토큰 등)에 대한 테스트도 추가하면 더욱 완성도 높은 테스트가 될 것입니다.

src/main/java/team/wego/wegobackend/common/security/SecurityConfig.java (2)

38-43: CSRF 비활성화 확인

Stateless JWT 기반 API에서 CSRF 비활성화는 적절합니다. 다만, 향후 쿠키 기반 인증(Refresh Token 등)을 도입할 경우 CSRF 보호 재검토가 필요합니다.


49-50: JWT 필터 설정 적절함

UsernamePasswordAuthenticationFilter 앞에 JWT 필터를 배치하여 토큰 기반 인증이 먼저 처리되도록 올바르게 구성되었습니다.

src/main/java/team/wego/wegobackend/common/security/CustomUserDetailsService.java (1)

25-31: LGTM!

Spring Security의 UserDetails 빌더를 올바르게 사용하고 있으며, ROLE_ 접두사가 적절히 적용되어 있습니다.

src/main/java/team/wego/wegobackend/user/repository/UserRepository.java (1)

7-12: UserRepository interface follows Spring Data JPA conventions effectively.

The naming of existsByEmail() and findByEmail() is idiomatic and will be auto-implemented by Spring Data JPA. The email field in the User entity is properly configured with unique = true (line 30 of User.java), which ensures data integrity and makes these query methods efficient for authentication and duplicate-check operations.

src/main/java/team/wego/wegobackend/common/entity/BaseTimeEntity.java (1)

13-24: 감사(Auditing) 기본 엔티티 구성이 표준적입니다

@MappedSuperclass + AuditingEntityListener + @CreatedDate/@LastModifiedDate 패턴이 잘 적용되어 있고, createdAtupdatable = false 설정도 적절해 보입니다. User 등 도메인 엔티티에서 상속해 사용하는 용도에 무리가 없어 보입니다.

src/main/java/team/wego/wegobackend/common/security/jwt/JwtTokenProvider.java (1)

40-63: 액세스/리프레시 토큰 생성 구조는 명확하고 확장 가능해 보입니다.

subject 에 이메일을 두고, type 으로 access/refresh 를 구분하며, role 은 선택적으로 claim 에 넣는 구조가 깔끔합니다. createToken 으로 공통 로직을 모아둔 것도 좋고, HS256 + SecretKey 사용도 jjwt 최신 API 사용 방식과 잘 맞습니다. 이 부분은 현재 형태 그대로 사용해도 무방해 보입니다.

Comment on lines 100 to 120
private void logJwtSettings() {
log.info("🔐 JWT SETTINGS:");

String secret = env.getProperty("jwt.secret");
if (secret != null) {
log.info(" - Secret Key: {}... (length: {})",
secret.substring(0, Math.min(10, secret.length())),
secret.length()
);
} else {
log.warn(" - Secret Key: NOT CONFIGURED!");
}

String expiration = env.getProperty("jwt.expiration");
if (expiration != null) {
long expirationMs = Long.parseLong(expiration);
long hours = expirationMs / (1000 * 60 * 60);
log.info(" - Token Expiration: {} ms ({} hours)", expirationMs, hours);
} else {
log.warn(" - Token Expiration: NOT CONFIGURED!");
}
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

JWT 설정 로깅에서 시크릿 노출 및 프로퍼티 키 불일치 문제가 있습니다

  1. 시크릿 일부 로깅 (보안 이슈)
    jwt.secret의 앞 10자를 그대로 로그에 남기고 있어, 로그 유출 시 공격자에게 비밀번호 힌트를 제공하는 효과가 날 수 있습니다. 운영 환경까지 같은 로거를 사용할 것을 생각하면, 시크릿의 값 자체는 전혀 찍지 않는 편이 안전합니다(길이 정도만 노출).

  2. 만료 시간 프로퍼티 키 불일치 (설정 오인 가능)
    현재 코드는 jwt.expiration을 읽지만, application.yml에는
    jwt.access.token.expiration, jwt.refresh.token.expiration만 정의되어 있어 항상 “NOT CONFIGURED!”로만 찍힐 것입니다. 실제로는 설정이 되어 있는데 로그 상으로는 안 된 것처럼 보여서 디버깅 시 혼란을 줄 수 있습니다.

아래처럼 수정하면 두 문제를 한 번에 해소할 수 있습니다.

     private void logJwtSettings() {
         log.info("🔐 JWT SETTINGS:");

         String secret = env.getProperty("jwt.secret");
-        if (secret != null) {
-            log.info("   - Secret Key: {}... (length: {})",
-                secret.substring(0, Math.min(10, secret.length())),
-                secret.length()
-            );
-        } else {
-            log.warn("   - Secret Key: NOT CONFIGURED!");
-        }
-
-        String expiration = env.getProperty("jwt.expiration");
-        if (expiration != null) {
-            long expirationMs = Long.parseLong(expiration);
-            long hours = expirationMs / (1000 * 60 * 60);
-            log.info("   - Token Expiration: {} ms ({} hours)", expirationMs, hours);
-        } else {
-            log.warn("   - Token Expiration: NOT CONFIGURED!");
-        }
+        if (secret != null && !secret.isBlank()) {
+            log.info("   - Secret Key: [CONFIGURED] (length: {})", secret.length());
+        } else {
+            log.warn("   - Secret Key: NOT CONFIGURED!");
+        }
+
+        String accessExpiration = env.getProperty("jwt.access.token.expiration");
+        if (accessExpiration != null) {
+            long expirationMs = Long.parseLong(accessExpiration);
+            long hours = expirationMs / (1000 * 60 * 60);
+            log.info("   - Access Token Expiration: {} ms ({} hours)", expirationMs, hours);
+        } else {
+            log.warn("   - Access Token Expiration: NOT CONFIGURED!");
+        }
+
+        String refreshExpiration = env.getProperty("jwt.refresh.token.expiration");
+        if (refreshExpiration != null) {
+            long expirationMs = Long.parseLong(refreshExpiration);
+            long hours = expirationMs / (1000 * 60 * 60);
+            log.info("   - Refresh Token Expiration: {} ms ({} hours)", expirationMs, hours);
+        } else {
+            log.warn("   - Refresh Token Expiration: NOT CONFIGURED!");
+        }
     }

이렇게 하면 시크릿 값 노출 없이, 설정된 access/refresh 만료 시간 정보를 정확히 확인할 수 있습니다.

📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
private void logJwtSettings() {
log.info("🔐 JWT SETTINGS:");
String secret = env.getProperty("jwt.secret");
if (secret != null) {
log.info(" - Secret Key: {}... (length: {})",
secret.substring(0, Math.min(10, secret.length())),
secret.length()
);
} else {
log.warn(" - Secret Key: NOT CONFIGURED!");
}
String expiration = env.getProperty("jwt.expiration");
if (expiration != null) {
long expirationMs = Long.parseLong(expiration);
long hours = expirationMs / (1000 * 60 * 60);
log.info(" - Token Expiration: {} ms ({} hours)", expirationMs, hours);
} else {
log.warn(" - Token Expiration: NOT CONFIGURED!");
}
private void logJwtSettings() {
log.info("🔐 JWT SETTINGS:");
String secret = env.getProperty("jwt.secret");
if (secret != null && !secret.isBlank()) {
log.info(" - Secret Key: [CONFIGURED] (length: {})", secret.length());
} else {
log.warn(" - Secret Key: NOT CONFIGURED!");
}
String accessExpiration = env.getProperty("jwt.access.token.expiration");
if (accessExpiration != null) {
long expirationMs = Long.parseLong(accessExpiration);
long hours = expirationMs / (1000 * 60 * 60);
log.info(" - Access Token Expiration: {} ms ({} hours)", expirationMs, hours);
} else {
log.warn(" - Access Token Expiration: NOT CONFIGURED!");
}
String refreshExpiration = env.getProperty("jwt.refresh.token.expiration");
if (refreshExpiration != null) {
long expirationMs = Long.parseLong(refreshExpiration);
long hours = expirationMs / (1000 * 60 * 60);
log.info(" - Refresh Token Expiration: {} ms ({} hours)", expirationMs, hours);
} else {
log.warn(" - Refresh Token Expiration: NOT CONFIGURED!");
}
}

Comment on lines +32 to +36
.authorizeHttpRequests((auth) -> auth
.requestMatchers(PathRequest.toH2Console()).permitAll()
.requestMatchers(SecurityEndpoints.PUBLIC_PATTERNS).permitAll()
.anyRequest().authenticated()
);
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

H2 Console 접근 제한: 프로덕션 환경 고려 필요

H2 Console에 대한 permitAll() 설정이 있습니다. 개발 환경에서는 유용하지만, 프로덕션 환경에서는 보안 위험이 됩니다. 프로파일 기반으로 H2 Console 접근을 제한하는 것을 권장합니다.

+            // H2 Console은 개발 환경에서만 허용되어야 함
             .requestMatchers(PathRequest.toH2Console()).permitAll()

프로덕션 배포 전에 H2 Console 비활성화 또는 프로파일 분리가 필요합니다.

Committable suggestion skipped: line range outside the PR's diff.

🤖 Prompt for AI Agents
In src/main/java/team/wego/wegobackend/common/security/SecurityConfig.java
around lines 32-36, the H2 Console is currently exposed via
requestMatchers(PathRequest.toH2Console()).permitAll(), which is unsafe for
production; update the configuration to apply that permitAll only when a
non-production profile is active (e.g., "dev" or "test") by injecting Spring's
Environment (or using @Profile) and conditionally adding the
PathRequest.toH2Console() matcher inside the HttpSecurity configuration when the
active profiles include your dev/test profile(s); ensure the H2-specific
frameOptions/csrf relaxations (if present) are also only applied under the same
profile so the console is disabled in production.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🧹 Nitpick comments (2)
src/main/java/team/wego/wegobackend/user/application/dto/response/UserInfoResponse.java (1)

12-54: 이전 리뷰 피드백 반영 완료 및 구현 양호

이전 리뷰에서 지적된 createAt 오타가 createdAt으로 수정되어 일관성이 확보되었습니다. DTO 구조와 빌더 패턴 사용이 적절하며, 팩토리 메서드를 통한 변환 로직도 명확합니다.

선택적 개선 사항: Boolean 필드명 "is" 접두사 제거 고려

Lines 34, 36의 isNotificationEnabled, isDeleted 필드명은 Java 관례상 "is" 접두사를 제거하는 것이 권장됩니다. Lombok이 자동으로 getter에 "is"나 "get"을 추가하기 때문에, 필드명 자체에 "is"가 있으면 getIsDeleted()처럼 다소 어색한 메서드명이 생성됩니다.

필드명을 notificationEnabled, deleted로 변경하면 더 자연스러운 getter가 생성됩니다:

-    private Boolean isNotificationEnabled;
+    private Boolean notificationEnabled;

-    private Boolean isDeleted;
+    private Boolean deleted;

그리고 빌더 호출 부분도 함께 수정:

-            .isNotificationEnabled(user.getNotificationEnabled())
-            .isDeleted(user.getDeleted())
+            .notificationEnabled(user.getNotificationEnabled())
+            .deleted(user.getDeleted())
src/main/java/team/wego/wegobackend/common/config/ApplicationStartupLogger.java (1)

100-111: JWT 만료 시간 로깅을 access/refresh 분리 및 파싱 오류 방어 로직으로 확장하면 더 안정적입니다

현재는 jwt.access.token.expiration 하나만 로깅하고, Long.parseLong 실패 시 애플리케이션 준비 이벤트 처리 단계에서 런타임 예외가 그대로 전파될 수 있습니다. access/refresh 를 각각 로깅하고, 잘못된 설정값에 대해서는 예외 대신 에러 로그를 남기는 형태가 운영 관점에서 조금 더 안전할 것 같습니다.

예시 리팩터:

-    private void logJwtSettings() {
-        log.info("🔐 JWT SETTINGS:");
-
-        String expiration = env.getProperty("jwt.access.token.expiration");
-        if (expiration != null) {
-            long expirationMs = Long.parseLong(expiration);
-            long hours = expirationMs / (1000 * 60 * 60);
-            log.info("   - Token Expiration: {} ms ({} hours)", expirationMs, hours);
-        } else {
-            log.warn("   - Token Expiration: NOT CONFIGURED!");
-        }
-    }
+    private void logJwtSettings() {
+        log.info("🔐 JWT SETTINGS:");
+
+        logTokenExpiration("Access", "jwt.access.token.expiration");
+        logTokenExpiration("Refresh", "jwt.refresh.token.expiration");
+    }
+
+    private void logTokenExpiration(String label, String propertyKey) {
+        String expiration = env.getProperty(propertyKey);
+        if (expiration == null || expiration.isBlank()) {
+            log.warn("   - {} Token Expiration: NOT CONFIGURED! (property: {})", label, propertyKey);
+            return;
+        }
+        try {
+            long expirationMs = Long.parseLong(expiration);
+            long hours = expirationMs / (1000 * 60 * 60);
+            log.info("   - {} Token Expiration: {} ms ({} hours)", label, expirationMs, hours);
+        } catch (NumberFormatException e) {
+            log.error("   - {} Token Expiration: INVALID VALUE '{}' (property: {})", label, expiration, propertyKey);
+        }
+    }

이렇게 하면:

  • access/refresh 토큰 만료 시간을 각각 확인할 수 있고,
  • 잘못된 설정값이 있더라도 애플리케이션 시작은 유지하면서 로그로 명확히 진단할 수 있습니다.

참고로, 이전 리뷰에서 지적되었던 jwt.secret 값 일부 노출 문제는 현재 코드에서는 제거된 상태라 보안 측면에서 더 안전해진 것으로 보입니다.

📜 Review details

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between f476cd0 and facc9ab.

📒 Files selected for processing (2)
  • src/main/java/team/wego/wegobackend/common/config/ApplicationStartupLogger.java (1 hunks)
  • src/main/java/team/wego/wegobackend/user/application/dto/response/UserInfoResponse.java (1 hunks)
🔇 Additional comments (1)
src/main/java/team/wego/wegobackend/common/config/ApplicationStartupLogger.java (1)

22-44: 스타트업 로깅 엔트리 포인트 구조가 명확하고 책임 분리가 잘 되어 있습니다

ApplicationReadyEvent 리스너에서 프로필/DB/JPA/JWT/서버 정보를 각 전용 메서드로 위임하는 구조가 이해하기 쉽고, 실제 비즈니스 빈에서 진단용 로깅을 분리한 점이 좋습니다. 운영 시에도 장애 원인 파악에 유용할 것 같습니다.

Comment on lines +58 to +82
private void logDatabaseInfo() {
try (Connection connection = dataSource.getConnection()) {
DatabaseMetaData metaData = connection.getMetaData();

log.info("🗄️ DATABASE INFORMATION:");
log.info(" - Database Type: {} {}",
metaData.getDatabaseProductName(),
metaData.getDatabaseProductVersion()
);
log.info(" - JDBC Driver: {} {}",
metaData.getDriverName(),
metaData.getDriverVersion()
);
log.info(" - Connection URL: {}",
maskPassword(metaData.getURL())
);
log.info(" - Username: {}", metaData.getUserName());
log.info(" - Max Connections: {}",
env.getProperty("spring.datasource.hikari.maximum-pool-size", "10")
);

} catch (Exception e) {
log.error("❌ Failed to retrieve database information", e);
}
}
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

🧩 Analysis chain

🏁 Script executed:

find . -type f -name "ApplicationStartupLogger.java" | head -5

Repository: WeGo-Together/WeGo_BackEnd

Length of output: 151


🏁 Script executed:

cat -n src/main/java/team/wego/wegobackend/common/config/ApplicationStartupLogger.java

Repository: WeGo-Together/WeGo_BackEnd

Length of output: 5513


🌐 Web query:

JDBC DatabaseMetaData getURL() null behavior specification

💡 Result:

The JDBC spec (DatabaseMetaData.getURL()) says the method "retrieves the URL for this DBMS" and may return the URL or null if it cannot be generated — i.e., drivers are allowed to return null when they cannot determine/produce a URL. See the DatabaseMetaData javadoc. [1][2]

Sources

  • java.sql.DatabaseMetaData.getURL() javadoc (Java SE): "the URL for this DBMS or null if it cannot be generated." [1]
  • Oracle JDBC DatabaseMetaData javadoc: "Returns: the url or null if it can't be generated." [2]

[1] https://docs.oracle.com/en/java/javase/11/docs/api/java.sql/java/sql/DatabaseMetaData.html
[2] https://docs.oracle.com/database/ (Oracle JDBC DatabaseMetaData getURL documentation)


🌐 Web query:

Java String replaceAll null pointer exception behavior

💡 Result:

Short answer: String.replaceAll delegates to Pattern.compile(regex).matcher(this).replaceAll(repl). So:

  • If the regex argument is null you get a NullPointerException (Pattern.compile(null) → NPE). [1][2]
  • If you call replaceAll on a null String reference you'll also get a NullPointerException (calling any instance method on null). [1]
  • If the replacement argument is null the Matcher.replaceAll/replaceFirst implementation throws a NullPointerException. [2][3]

References:

  1. java.lang.String.replaceAll javadoc / description. [Oracle Java docs]. [1]
  2. java.util.regex.Pattern / Matcher behavior (Pattern.compile and Matcher.replaceAll). [Oracle Java docs]. [2]
  3. Matcher.replaceFirst source / docs showing explicit NPE on null replacement. [3]

(If you want, I can paste minimal example code demonstrating each case.)


🌐 Web query:

JDBC URL password parameter naming conventions case sensitivity

💡 Result:

Short answer: JDBC URL parameter names (including the password key) are driver-defined and not guaranteed to be treated the same across all drivers — their spelling and case-sensitivity depend on the driver’s parser. Common conventions are user/username and password or pwd, but you must check the driver docs for the exact accepted key(s) and whether the driver normalizes case.

Key points and sources:

  • Driver-specific: each JDBC driver documents the accepted URL/property names (e.g., PostgreSQL lists PASSWORD / PGProperty.PASSWORD; the driver code/Docs show which keys it accepts). [1]
  • Java Properties itself uses case‑sensitive String keys, so if a driver reads a java.util.Properties object directly the exact key case matters unless the driver normalizes it. [2]
  • Oracle’s JDBC docs show credentials may be provided via Properties or getConnection arguments; the server’s password case-sensitivity is a separate concern (database password matching can be case‑sensitive or configurable). [3][4]

Recommendation: consult the specific JDBC driver documentation (and/or inspect the driver’s PGProperty/constant names or source) to know the exact key names and whether the driver lowercases/normalizes parameter names. Examples: PostgreSQL PGProperty docs and Oracle JDBC docs. [1][3]

Sources:

  1. PostgreSQL JDBC PGProperty documentation (lists PASSWORD/PGProperty.PASSWORD). [https://jdbc.postgresql.org/documentation/publicapi/org/postgresql/PGProperty.html] [1]
  2. Java/Properties keys are case‑sensitive (Java design/FAQ discussion about case-sensitive property keys). [https://docs.oracle.com/en/java/javase/24/core/design-faq.html] [2]
  3. Oracle JDBC client/login docs (credentials via Properties or getConnection; server-side password case rules). [https://docs.oracle.com/en/database/oracle/oracle-database/26/jjdbc/client-side-security.html] [3]
  4. Oracle Database authentication: SEC_CASE_SENSITIVE_LOGON (password case-sensitivity controlled by DB setting). [https://docs.oracle.com/cd/E15586_01/network.1111/e16543/authentication.htm] [4]

Add null check to maskPassword() method to prevent NPE when DatabaseMetaData.getURL() returns null

Some JDBC drivers return null from DatabaseMetaData.getURL(), and calling url.replaceAll() on null will throw a NullPointerException. This should be handled defensively in the logging helper:

    private String maskPassword(String url) {
-       // URL에서 비밀번호 마스킹
-       return url.replaceAll("password=[^&;]+", "password=****");
+       if (url == null || url.isBlank()) {
+           return "N/A";
+       }
+       // URL에서 비밀번호 마스킹
+       return url.replaceAll("password=[^&;]+", "password=****");
    }

This ensures database information is logged safely regardless of whether the driver provides a URL.

Committable suggestion skipped: line range outside the PR's diff.

🤖 Prompt for AI Agents
In
src/main/java/team/wego/wegobackend/common/config/ApplicationStartupLogger.java
around lines 58 to 82, guard against a potential NPE when metaData.getURL() can
be null by making maskPassword null-safe: check if the URL is null (or blank)
and return a safe placeholder such as "N/A" (or an empty string) instead of
calling replaceAll on it; update the logDatabaseInfo call to pass the result of
the null-safe maskPassword unchanged so logging will never attempt to operate on
a null URL.

@Be-HinD
Copy link
Member Author

Be-HinD commented Dec 7, 2025

아래 작업 추가 진행하고 있습니다.

  • refresh 인증 분리
  • access 재발급 엔드포인트 개발

- API 인가 refresh 분기처리 추가
- accesstoken 재발급 엔드포인트 개발
- Refresh Token JSON -> Cookie 변경 (secure, httponly 설정)
- .http 테스트 코드 작성
Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

♻️ Duplicate comments (1)
src/main/java/team/wego/wegobackend/auth/application/dto/response/RefreshResponse.java (1)

10-32: LoginResponse와 동일한 패턴이 반복됩니다.

이 응답 구조는 LoginResponse와 매우 유사한 토큰 응답 패턴을 공유합니다.

앞서 LoginResponse.java 리뷰에서 언급한 것처럼, 공통 부분을 추출하여 코드 중복을 줄이는 것을 권장합니다.

🧹 Nitpick comments (5)
src/main/java/team/wego/wegobackend/auth/application/dto/response/LoginResponse.java (1)

14-44: 구조는 양호하나 RefreshResponse와 코드 중복이 있습니다.

DTO 구조와 @JsonIgnore를 통한 refreshToken 보안 처리는 적절합니다. 다만 RefreshResponse와 동일한 패턴(tokenType="Bearer", expiresAt 계산 로직)이 반복되고 있습니다.

향후 유지보수성 향상을 위해 공통 토큰 응답 필드를 base class나 composition으로 추출하는 것을 고려해보세요:

@Getter
@SuperBuilder
public abstract class TokenResponse {
    private String tokenType = "Bearer";
    private Long expiresIn;
    private LocalDateTime expiresAt;
    
    protected static LocalDateTime calculateExpiresAt(Long expiresIn) {
        return LocalDateTime.now().plusSeconds(expiresIn);
    }
}
src/main/java/team/wego/wegobackend/auth/application/AuthService.java (1)

65-67: 탈퇴 계정 검증 로직이 중복됩니다.

loginrefresh 메서드 모두에서 동일한 탈퇴 계정 체크가 반복됩니다.

공통 검증 메서드로 추출하세요:

private void validateActiveUser(User user) {
    if (user.getDeleted()) {
        throw new IllegalArgumentException("탈퇴한 계정");
    }
}

그리고 두 곳에서 validateActiveUser(user);로 호출하세요.

Also applies to: 93-95

src/main/java/team/wego/wegobackend/auth/presentation/AuthController.java (2)

57-68: Refresh 엔드포인트 구현이 적절하나 간소화 가능합니다.

쿠키 검증 로직이 올바르게 동작합니다.

required=false와 수동 null 체크 대신 더 간결하게 처리할 수 있습니다:

@PostMapping("/refresh")
public ResponseEntity<RefreshResponse> refresh(
    @CookieValue(name = "refreshToken") String refreshToken
) {
    RefreshResponse response = authService.refresh(refreshToken);
    return ResponseEntity.ok(response);
}

Spring이 쿠키가 없을 때 자동으로 400 에러를 반환하며, 커스텀 예외 핸들러에서 처리할 수 있습니다.


73-81: 쿠키 설정이 보안 요구사항을 충족합니다.

HttpOnly, Secure, SameSite 설정이 모두 적용되어 XSS 및 CSRF 공격에 대한 방어가 구현되었습니다.

Spring 6+를 사용한다면 ResponseCookie를 고려해보세요:

private ResponseCookie createRefreshTokenCookie(String refreshToken) {
    return ResponseCookie.from("refreshToken", refreshToken)
        .httpOnly(true)
        .secure(true)
        .path("/")
        .maxAge(jwtTokenProvider.getRefreshTokenExpiration())
        .sameSite("Strict")
        .build();
}

그리고 response.addHeader(HttpHeaders.SET_COOKIE, cookie.toString());로 추가합니다.

src/main/java/team/wego/wegobackend/common/security/jwt/JwtTokenProvider.java (1)

117-154: 이전 보안 취약점이 완전히 해결되었습니다.

validateAccessTokenvalidateRefreshToken 메서드가 토큰 타입을 명시적으로 검증하여, 이전 리뷰에서 지적된 refresh 토큰이 access 토큰처럼 사용될 수 있는 critical 보안 이슈를 차단합니다.

에러 로깅 개선을 위해 예외 세부사항을 포함하세요:

         } catch (Exception e) {
-            log.error("Error validating access token type");
+            log.error("Error validating access token type", e);
             return false;
         }

Lines 130과 151에 동일하게 적용하세요.

📜 Review details

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between facc9ab and 878aa66.

📒 Files selected for processing (7)
  • src/main/java/team/wego/wegobackend/auth/application/AuthService.java (1 hunks)
  • src/main/java/team/wego/wegobackend/auth/application/dto/response/LoginResponse.java (1 hunks)
  • src/main/java/team/wego/wegobackend/auth/application/dto/response/RefreshResponse.java (1 hunks)
  • src/main/java/team/wego/wegobackend/auth/presentation/AuthController.java (1 hunks)
  • src/main/java/team/wego/wegobackend/common/security/JwtAuthenticationFilter.java (1 hunks)
  • src/main/java/team/wego/wegobackend/common/security/jwt/JwtTokenProvider.java (1 hunks)
  • src/test/http/auth/auth-api.http (1 hunks)
🧰 Additional context used
🧬 Code graph analysis (3)
src/main/java/team/wego/wegobackend/auth/application/AuthService.java (1)
src/main/java/team/wego/wegobackend/common/security/CustomUserDetailsService.java (1)
  • Service (14-33)
src/main/java/team/wego/wegobackend/auth/application/dto/response/LoginResponse.java (4)
src/main/java/team/wego/wegobackend/auth/application/dto/response/RefreshResponse.java (1)
  • Getter (10-33)
src/main/java/team/wego/wegobackend/auth/application/dto/request/LoginRequest.java (1)
  • Getter (8-18)
src/main/java/team/wego/wegobackend/auth/application/dto/request/SignupRequest.java (1)
  • Getter (9-26)
src/main/java/team/wego/wegobackend/auth/application/dto/response/SignupResponse.java (1)
  • Getter (12-38)
src/main/java/team/wego/wegobackend/auth/application/dto/response/RefreshResponse.java (1)
src/main/java/team/wego/wegobackend/auth/application/dto/response/LoginResponse.java (1)
  • Getter (14-45)
🪛 ast-grep (0.40.0)
src/main/java/team/wego/wegobackend/auth/presentation/AuthController.java

[warning] 48-48: The application does not appear to verify inbound requests which can lead to a Cross-site request forgery (CSRF) vulnerability. If the application uses cookie-based authentication, an attacker can trick users into sending authenticated HTTP requests without their knowledge from any arbitrary domain they visit. To prevent this vulnerability start by identifying if the framework or library leveraged has built-in features or offers plugins for CSRF protection. CSRF tokens should be unique and securely random. The Synchronizer Token or Double Submit Cookie patterns with defense-in-depth mechanisms such as the sameSite cookie flag can help prevent CSRF. For more information, see: [Cross-site request forgery prevention](https://cheatsheetseries.owasp.org/cheatsheets/Cross-Site_Req\ uest_Forgery_Prevention_Cheat_Sheet.html).
Context: response.addCookie(createRefreshTokenCookie(loginResponse.getRefreshToken()));
Note: [CWE-352] Cross-Site Request Forgery (CSRF). [REFERENCES]
- https://stackoverflow.com/questions/42717210/samesite-cookie-in-java-application

(cookie-missing-samesite-java)


[warning] 48-48: A cookie was detected without setting the 'HttpOnly' flag. The 'HttpOnly' flag for cookies instructs the browser to forbid client-side scripts from reading the cookie. Set the 'HttpOnly' flag by calling 'cookie.setHttpOnly(true);
Context: response.addCookie(createRefreshTokenCookie(loginResponse.getRefreshToken()));
Note: [CWE-1004] Sensitive Cookie Without 'HttpOnly' Flag. [REFERENCES]
- https://owasp.org/www-community/HttpOnly

(cookie-missing-httponly-java)

🔇 Additional comments (6)
src/main/java/team/wego/wegobackend/common/security/JwtAuthenticationFilter.java (1)

27-58: 이전 보안 이슈가 적절히 해결되었습니다.

validateAccessToken 메서드를 사용하여 access 토큰만 인증에 사용되도록 보장합니다. 이는 이전 리뷰에서 지적된 refresh 토큰 오용 가능성을 차단합니다.

필터 로직과 예외 처리가 적절하며, SecurityContext 설정도 올바르게 구현되었습니다.

src/main/java/team/wego/wegobackend/auth/application/AuthService.java (1)

36-51: 회원가입 로직이 올바르게 구현되었습니다.

이메일 중복 체크, 비밀번호 암호화, 기본 역할 설정이 적절합니다.

src/main/java/team/wego/wegobackend/auth/presentation/AuthController.java (2)

35-39: 회원가입 엔드포인트가 올바르게 구현되었습니다.

요청 검증과 서비스 계층 위임이 적절합니다.


44-52: 로그인 엔드포인트와 쿠키 처리가 적절합니다.

Refresh token을 HttpOnly, Secure, SameSite=Strict 쿠키로 설정하는 것은 보안 모범 사례입니다. 정적 분석 경고는 **오탐(false positive)**입니다 - 코드가 이미 HttpOnly(line 75)와 SameSite(line 79)를 설정하고 있습니다.

src/main/java/team/wego/wegobackend/common/security/jwt/JwtTokenProvider.java (2)

32-35: 시크릿 키 초기화가 올바르게 구현되었습니다.

@PostConstruct를 사용한 지연 초기화와 Base64 디코딩이 적절합니다.


40-63: 토큰 생성 로직이 보안 요구사항을 충족합니다.

Access 토큰과 refresh 토큰을 type 클레임으로 명확히 구분하고, role은 access 토큰에만 포함하는 설계가 적절합니다.

Comment on lines +56 to +77
public LoginResponse login(LoginRequest request) {

User user = userRepository.findByEmail(request.getEmail())
.orElseThrow(() -> new IllegalArgumentException("존재하지 않는 사용자"));

if (!passwordEncoder.matches(request.getPassword(), user.getPassword())) {
throw new IllegalArgumentException("잘못된 비밀번호");
}

if (user.getDeleted()) {
throw new IllegalArgumentException("탈퇴한 계정");
}

String accessToken = jwtTokenProvider.createAccessToken(user.getEmail(),
user.getRole().name());

String refreshToken = jwtTokenProvider.createRefreshToken(user.getEmail());

Long expiresIn = jwtTokenProvider.getAccessTokenExpiresIn();

return LoginResponse.of(user, accessToken, refreshToken, expiresIn);
}
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion | 🟠 Major

로그인 검증 로직은 정확하나 에러 처리 개선이 필요합니다.

비밀번호 검증 및 계정 상태 확인이 올바르게 구현되었습니다. 다만 모든 비즈니스 예외를 IllegalArgumentException으로 처리하는 것은 PR 목표에 명시된 대로 개선이 필요합니다.

커스텀 예외를 도입하여 에러 케이스를 명확히 구분하세요:

// 예시
throw new UserNotFoundException("존재하지 않는 사용자");
throw new InvalidPasswordException("잘못된 비밀번호");
throw new DeletedAccountException("탈퇴한 계정");

이는 PR 설명의 TO-DO 항목("커스텀 예외 처리 적용")과 일치합니다.

🤖 Prompt for AI Agents
In src/main/java/team/wego/wegobackend/auth/application/AuthService.java around
lines 56 to 77, replace the three IllegalArgumentException usages with
domain-specific custom exceptions to improve error clarity: throw new
UserNotFoundException("존재하지 않는 사용자") when the user is not found, throw new
InvalidPasswordException("잘못된 비밀번호") when the password check fails, and throw
new DeletedAccountException("탈퇴한 계정") when the account is marked deleted; create
these exception classes (e.g., extending RuntimeException or a common
BusinessException) in an appropriate package, add the necessary imports, and
ensure existing callers/tests are updated to expect the new exception types if
necessary.

Comment on lines +25 to +27
### 액세스 토큰 재발급
POST http://localhost:8080/api/v1/auth/refresh
Content-Type: application/json
Copy link

@coderabbitai coderabbitai bot Dec 7, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

Refresh 엔드포인트 테스트가 불완전합니다.

현재 refresh 요청은 본문이 비어 있지만, AuthController/refresh 엔드포인트는 refreshToken 쿠키를 요구합니다. 로그인 응답에서 설정된 쿠키가 자동으로 전달되지 않으면 이 테스트는 실패합니다.

HTTP 클라이언트가 쿠키를 자동으로 관리하지 않는 경우, 다음과 같이 명시적으로 쿠키를 전달해야 합니다:

 ### 액세스 토큰 재발급
 POST http://localhost:8080/api/v1/auth/refresh
 Content-Type: application/json
+Cookie: refreshToken={{refreshToken}}

또는 로그인 응답에서 refreshToken을 추출하여 변수로 저장하는 스크립트를 추가할 수 있습니다.

📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
### 액세스 토큰 재발급
POST http://localhost:8080/api/v1/auth/refresh
Content-Type: application/json
### 액세스 토큰 재발급
POST http://localhost:8080/api/v1/auth/refresh
Content-Type: application/json
Cookie: refreshToken={{refreshToken}}
🤖 Prompt for AI Agents
In src/test/http/auth/auth-api.http around lines 25-27, the refresh token test
sends an empty body but the /refresh endpoint expects a refreshToken cookie;
update the test to include the refreshToken cookie (either by adding a Cookie
header with the stored refresh token value from the prior login response, or by
extracting the refresh token from the login response and saving it to a variable
and then sending that variable as the Cookie) so the request includes the same
refreshToken cookie used by the application.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

InteliJ 에딧 사용 시 자동 세팅 됩니다. <참고>

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@Be-HinD, 알려주셔서 감사합니다! IntelliJ HTTP 클라이언트가 동일 파일 내의 요청들 간에 쿠키를 자동으로 관리한다는 점을 이해했습니다. 로그인 응답에서 설정된 refreshToken 쿠키가 자동으로 후속 요청에 포함되므로, 명시적인 Cookie 헤더가 필요하지 않네요.

이 정보를 참고하도록 하겠습니다! 🙏


✏️ Learnings added
Learnt from: Be-HinD
Repo: WeGo-Together/WeGo_BackEnd PR: 32
File: src/test/http/auth/auth-api.http:25-27
Timestamp: 2025-12-07T11:11:53.271Z
Learning: IntelliJ HTTP client (.http files) automatically manages cookies between requests in the same file. When reviewing .http test files, a refresh token endpoint test does not need an explicit Cookie header because cookies from previous requests (e.g., login) are automatically included by the IDE.

Note: Learnings are effective only in the context of similar code segments. To apply general coding guidelines, please configure review instructions. You can manage existing learnings in the app.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 0

🧹 Nitpick comments (3)
src/main/java/team/wego/wegobackend/auth/presentation/AuthController.java (3)

44-52: Refresh 토큰 쿠키 설정 전반은 좋지만, 만료 시간 단위/오버플로 검증이 필요해 보입니다.

  • createRefreshTokenCookie에서 HttpOnly, Secure, SameSite=Strict까지 잘 설정하셔서 정석적인 보안 설정입니다. 정적 분석 도구의 HttpOnly 미설정 경고는 이 헬퍼 메서드를 고려하지 않은 false positive로 보입니다.
  • 다만 cookie.setMaxAge((int) jwtTokenProvider.getRefreshTokenExpiration()); 부분은 getRefreshTokenExpiration()단위와 범위를 한 번 더 확인하는 게 좋겠습니다.
    • ms 단위 long을 그대로 넘기면 int 캐스팅 시 오버플로가 날 수 있고(예: 30일 ms는 Integer.MAX_VALUE 초과), setMaxAge는 초 단위를 기대합니다.
    • Duration을 반환하거나, 메서드 이름을 getRefreshTokenExpirationSeconds()처럼 의미가 드러나는 int 반환으로 바꾸는 것도 추천합니다.

Also applies to: 88-95


57-67: 로그아웃 시 삭제 쿠키에도 Secure/SameSite를 맞춰 주는 게 좋습니다.

현재 삭제용 쿠키는 HttpOnly만 설정되어 있고 Secure·SameSite는 빠져 있습니다.

Cookie deleteCookie = new Cookie("refreshToken", null);
deleteCookie.setPath("/");
deleteCookie.setMaxAge(0);
deleteCookie.setHttpOnly(true);
response.addCookie(deleteCookie);

실제 동작은 대부분의 브라우저에서 문제없겠지만,

  • 동일 이름의 기존 쿠키가 Secure, SameSite=Strict로 설정되어 있으므로,
  • 삭제 쿠키도 똑같이 보안 속성을 맞춰 두는 편이 안전하고, 정적 분석 경고도 해소됩니다.

예시:

-        Cookie deleteCookie = new Cookie("refreshToken", null);
-        deleteCookie.setPath("/");
-        deleteCookie.setMaxAge(0);
-        deleteCookie.setHttpOnly(true);
+        Cookie deleteCookie = new Cookie("refreshToken", null);
+        deleteCookie.setPath("/");
+        deleteCookie.setMaxAge(0);
+        deleteCookie.setHttpOnly(true);
+        deleteCookie.setSecure(true);
+        deleteCookie.setAttribute("SameSite", "Strict");

72-83: refresh 엔드포인트의 예외 타입/응답 코드를 명시적으로 처리하는 편이 좋습니다.

if (refreshToken == null) {
    throw new IllegalArgumentException("Refresh 토큰이 없습니다.");
}
  • 지금 상태라면 전역 예외 핸들러가 없을 경우 500으로 떨어질 수 있어, 클라이언트 입장에서 인증 실패(401/403 혹은 400) 상황과 구분이 어렵습니다.
  • 도메인에 맞는 커스텀 예외(예: InvalidRefreshTokenException) + @ResponseStatus 또는 공통 예외 핸들러에서 401/400으로 내려주는 쪽이 더 명확해 보입니다.
  • 이미 TODO에 “커스텀 예외 처리 적용”이 있으니, 이 부분을 우선 적용할 후보로 삼으시면 좋겠습니다.
📜 Review details

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 878aa66 and 09063f4.

📒 Files selected for processing (1)
  • src/main/java/team/wego/wegobackend/auth/presentation/AuthController.java (1 hunks)
🧰 Additional context used
🪛 ast-grep (0.40.0)
src/main/java/team/wego/wegobackend/auth/presentation/AuthController.java

[warning] 63-63: A cookie was detected without setting the 'secure' flag. The 'secure' flag for cookies prevents the client from transmitting the cookie over insecure channels such as HTTP. Set the 'secure' flag by calling '.setSecure(true);'.
Context: response.addCookie(deleteCookie);
Note: [CWE-614] Sensitive Cookie in HTTPS Session Without 'Secure' Attribute. [REFERENCES]
- https://owasp.org/www-community/controls/SecureCookieAttribute

(cookie-missing-secure-flag-java)


[warning] 48-48: A cookie was detected without setting the 'HttpOnly' flag. The 'HttpOnly' flag for cookies instructs the browser to forbid client-side scripts from reading the cookie. Set the 'HttpOnly' flag by calling 'cookie.setHttpOnly(true);
Context: response.addCookie(createRefreshTokenCookie(loginResponse.getRefreshToken()));
Note: [CWE-1004] Sensitive Cookie Without 'HttpOnly' Flag. [REFERENCES]
- https://owasp.org/www-community/HttpOnly

(cookie-missing-httponly-java)


[warning] 48-48: The application does not appear to verify inbound requests which can lead to a Cross-site request forgery (CSRF) vulnerability. If the application uses cookie-based authentication, an attacker can trick users into sending authenticated HTTP requests without their knowledge from any arbitrary domain they visit. To prevent this vulnerability start by identifying if the framework or library leveraged has built-in features or offers plugins for CSRF protection. CSRF tokens should be unique and securely random. The Synchronizer Token or Double Submit Cookie patterns with defense-in-depth mechanisms such as the sameSite cookie flag can help prevent CSRF. For more information, see: [Cross-site request forgery prevention](https://cheatsheetseries.owasp.org/cheatsheets/Cross-Site_Req\ uest_Forgery_Prevention_Cheat_Sheet.html).
Context: response.addCookie(createRefreshTokenCookie(loginResponse.getRefreshToken()));
Note: [CWE-352] Cross-Site Request Forgery (CSRF). [REFERENCES]
- https://stackoverflow.com/questions/42717210/samesite-cookie-in-java-application

(cookie-missing-samesite-java)


[warning] 63-63: The application does not appear to verify inbound requests which can lead to a Cross-site request forgery (CSRF) vulnerability. If the application uses cookie-based authentication, an attacker can trick users into sending authenticated HTTP requests without their knowledge from any arbitrary domain they visit. To prevent this vulnerability start by identifying if the framework or library leveraged has built-in features or offers plugins for CSRF protection. CSRF tokens should be unique and securely random. The Synchronizer Token or Double Submit Cookie patterns with defense-in-depth mechanisms such as the sameSite cookie flag can help prevent CSRF. For more information, see: [Cross-site request forgery prevention](https://cheatsheetseries.owasp.org/cheatsheets/Cross-Site_Req\ uest_Forgery_Prevention_Cheat_Sheet.html).
Context: response.addCookie(deleteCookie);
Note: [CWE-352] Cross-Site Request Forgery (CSRF). [REFERENCES]
- https://stackoverflow.com/questions/42717210/samesite-cookie-in-java-application

(cookie-missing-samesite-java)

@Be-HinD Be-HinD merged commit 3f3b72b into main Dec 7, 2025
1 check passed
@github-project-automation github-project-automation bot moved this from Backlog to Done in WeGo-Together Backend Dec 7, 2025
@Be-HinD Be-HinD deleted the feat/auth branch December 7, 2025 11:13
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

✨enhancement New feature or request

Projects

Status: Done

Development

Successfully merging this pull request may close these issues.

[FEAT] 인증/인가

1 participant