0161

BE

[Spring Boot] Network 탭엔 있는데, JS에선 undefined? Authorization 헤더가 안 보이는 진짜 이유

토큰 기반 인증 시스템을 구현하다가, 아주 애매한 상황을 하나 겪었다. 무려 2시간에 걸쳐서 말이다.

서버는 분명히 Authorization 헤더를 응답에 담아서 보내주는데, 클라이언트에서는 이게 undefined로 나오는 현상이었다...

? 문제 상황

프론트엔드(React)에서 axios로 로그인 요청을 보내고, Spring Boot 서버는 로그인 성공 후 Authorization: Bearer ... 형식으로 accessToken을 응답 헤더에 담아 보냈다.

그리고 프론트에서는 이렇게 꺼내려고 했다.

code
const token = response.headers["authorization"]; // ❌ undefined

근데... 아무리 찍어봐도 undefined였다.

심지어 개발자도구(Network 탭)에서는 Authorization 헤더가 잘 보이는데도 불구하고 말이다.

? 내가 해봤던 시도들

이상하다 싶어서 정말 별별 걸 다 해봤다.

  • ? 대소문자 문제인가? → authorization, Authorization 다 써봄

  • ? axios 설정 문제인가? → withCredentials: true 추가해봄

  • ? fetch로 바꾸면 될까? → fetch로도 해봤지만 여전히 안 보임

  • ? 혹시 응답에 body가 없어서 그런가? → .body("ok")도 넣어봄

  • ? X-Access-Token 같은 커스텀 헤더로 복사해서 응답해봄

...그런데도 여전히 JS 코드에서는 undefined만 계속 나왔다.

? 문제의 본질은 CORS + Spring Filter 우선순위

결국 찾아낸 핵심 원인은 이거였다.

Spring의 WebMvcConfigurer를 이용한 CORS 설정은 브라우저가 Authorization 헤더를 노출하는 데에는 영향을 주지 못했다는 점.

이렇게만 해서는 부족했다.

Java
@Override
public void addCorsMappings(CorsRegistry registry) {
    registry.addMapping("/api/**")
        .allowedOrigins("<http://localhost:3000>")
        .allowedHeaders("*")
        .allowedMethods("*")
        .exposedHeaders("Authorization")
        .allowCredentials(true);
}

설정은 맞는데... Spring Security나 필터 체인보다 늦게 동작해서 그런지, 브라우저는 여전히 해당 헤더를 자바스크립트에 보여주지 않았다.

✅ 진짜 해결책: CorsFilter 직접 등록하기

결국 적용한 해결 방법은 CorsFilter를 직접 Bean으로 등록하는 것이었다.

이 방식은 필터 체인 앞단에서 동작하기 때문에 훨씬 강력하다는 것도 알게 되곤 했다.

Java
@Bean
public CorsFilter corsFilter() {
    CorsConfiguration config = new CorsConfiguration();
    config.setAllowCredentials(true);
    config.addAllowedOrigin("<http://localhost:3000>");
    config.addAllowedHeader("*");
    config.addAllowedMethod("*");
    config.addExposedHeader("Authorization"); // ✅ 핵심!

    UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
    source.registerCorsConfiguration("/**", config);
    return new CorsFilter(source);
}

? 이렇게 해결됐다..

서버 재시작 후 다시 요청을 보내보니, axios의 response.headers["authorization"]에서 드디어 accessToken을 확인할 수 있었다..

그동안 삽질했던 게 싹 사라지는 순간이었다.. ?