
프로젝트를 진행하던 중 React와 Spring Boot를 연동해서 로그인 기능을 구현하려 했는데, 로그인은 성공했지만, 이후 마이페이지 API(/api/myPage/info) 요청 시 항상 401 Unauthorized가 떨어졌다.
axios.post('http://localhost:8080/api/member/login', data, {
withCredentials: true,
headers: { 'Content-Type': 'application/json' }
});
쿠키도 잘 저장됐고, JSESSIONID도 브라우저에 보였지만,
다음 요청에서 서버는 항상 principal == null로 판단하고 401을 반환했다.


session.setAttribute("SPRING_SECURITY_CONTEXT", SecurityContextHolder.getContext());
이걸 넣어줘야 Spring Security가 이후 요청에서 로그인 상태로 인식한다.
알고보니 Spring Security 5.7이상부터는 여러 개의 SecurityFilterChain을 만들 수 있다는 거였다. 이걸 알고나니 문제 해결이 수월해졌다. 리액트는 api/ 경로로 요청을 하기에 나는 .securityMatcher("/api/**") 을 적어준 뒤 그에 맞는 csrf, cors 로직을 짰다.
@Order(1)
@Bean
public SecurityFilterChain apiSecurity(HttpSecurity http) {
http.securityMatcher("/api/**")
.authorizeHttpRequests(auth -> auth.anyRequest().permitAll())
.formLogin(form -> form.disable());
return http.build();
}
@Order(2)
@Bean
public SecurityFilterChain webSecurity(HttpSecurity http) {
http.authorizeHttpRequests(auth -> auth.anyRequest().authenticated())
.formLogin(...) // 웹 로그인용
return http.build();
}
이번 문제는 정말 많은 사람들이 겪는 이슈다.
React와 Spring Security를 연동하려면 단순히 CORS만 해결하는 게 아니라,
세션과 SecurityContext까지 어떻게 연결되는지를 정확히 이해해야 인증이 유지된다.