백엔드/회고

[Swagger] Spring Boot Swagger 초기 설정 (feat. JWT 403 삽질기)

miniberry 2026. 3. 31. 11:53

1. 도입 배경

프로젝트를 진행하면서 API가 점점 많아지다 보니 이런 문제가 생겼다.

  • API 요청/응답 형식이 매번 헷갈림
  • 프론트와 협업할 때 명세 전달이 불편함
  • 테스트를 Postman으로 계속 날리는 게 번거로움

그래서 Swagger(OpenAPI)를 도입했다.


2. Swagger 적용 과정

이번 프로젝트에서는 아래 라이브러리를 사용했다.

implementation 'org.springdoc:springdoc-openapi-starter-webmvc-ui:2.3.0'

설치 후 서버를 실행하면

http://localhost:8080/swagger-ui/index.html
 

로 접속 가능하다.

여기까지는 정말 쉽다.
문제는 여기서부터 시작이었다.


3. 가장 큰 문제: 403 에러 (Undocumented)

Swagger에서 API를 실행하면 이런 에러가 발생했다.

403 Forbidden
Undocumented
 

처음엔 원인을 몰라서 한참 헤맸다.


4. 원인 분석

문제의 핵심은 Spring Security + JWT 필터였다.

내 구조는 이런 흐름이었다:

Swagger → API 요청 → JwtAuthenticationFilter → 인증 검사
 

근데 Swagger에서는 토큰을 안 넣고 요청을 보내기 때문에 JWT 필터에서 걸려버린다.

즉, Swagger 요청도 “인증 필요 요청”으로 처리된 것


5. 해결 방법

 1) Swagger 경로 허용

SecurityConfig에서 Swagger 관련 경로를 풀어줘야 한다.

http
	.authorizeHttpRequests(auth -> auth
		.requestMatchers(
            "/swagger-ui/**",
            "/v3/api-docs/**"
    	).permitAll()
	.anyRequest().authenticated()
);

 2) Swagger에서 JWT 사용 설정

단순히 열어주는 것만으로 끝이 아니다.
실제로 로그인 후 토큰을 넣어서 테스트해야 한다.

@SecurityRequirement(name = "bearerAuth")
 

그리고 Swagger 설정에 Bearer 인증 추가

@OpenAPIDefinition(
        security = @SecurityRequirement(name = "BearerAuth")
)

@SecurityScheme(
        name = "BearerAuth",
        type = SecuritySchemeType.HTTP,
        scheme = "bearer",
        bearerFormat = "JWT"
)

@Configuration
public class SwaggerConfig {

    @Bean
    public OpenAPI openAPI() {
        return new OpenAPI()
                .info(new Info()
                        .title("BenePicker API")
                        .description("BenePicker 백엔드 API 문서")
                        .version("v1.0.0")
                        .contact(new Contact()
                                .name("BenePicker Team")
                                .email("test@example.com"))
                        .license(new License()
                                .name("Apache 2.0")
                                .url("https://www.apache.org/licenses/LICENSE-2.0")))
                .externalDocs(new ExternalDocumentation()
                        .description("프로젝트 문서")
                        .url("https://example.com"));
    }
}
 

이후 Swagger UI에서 "Authorize" 버튼으로 토큰 입력 가능


 3) JwtFilter 디버깅 로그 추가

처음엔 왜 막히는지 몰랐는데 로그 찍으니까 바로 보였다.

System.out.println("Authorization: " + authorization);
 

여기서 알게 된 사실

  • Swagger 요청에는 Authorization 헤더 없음
  • 그래서 필터에서 바로 탈락

6. 동작 화면

BenePicker Swagger 예시

 


7. 깨달은 점

이번 경험에서 느낀 핵심은 다음과 같다.

 1) Swagger는 그냥 “문서 도구”가 아니다

→ 실제 요청을 보내는 클라이언트다


 2) Security와 붙으면 반드시 충돌한다

→ 인증/인가 흐름을 이해해야 한다


 3) 로그는 무조건 찍어야 한다

→ 감으로 디버깅하면 시간만 날린다


8. 다음 개선 방향

  • 공통 응답 구조 (CommonResponse) Swagger에 명세 추가
  • 에러 코드 문서화
  • API 태그 정리 (@Tag, @Operation)