I have a Spring-Boot back-end and a React front-end (written in Typescript and using the Axios HTTP client). Each of these applications is hosted on a different sub-domain of a common parent-domain.
I am attempting to use cookie-based authentication for the back-end and running into the following issue:
- A login request is made by the front-end and the back-end returns a response with a "Set-Cookie" header.
- On requests made to the back-end within the same "browser-window-session" (i.e. same tab, no page refreshes, etc), the browser includes the cookie that was set in step 1.
- If page is refreshed (or if the application is attempted to be accessed from a separate tab), the browser does not include any cookies in the requests made by the front-end.
More Context:
(with example URLs)
- The back-end is hosted at https://api.example.com
- The front-end is hosted at https://ui.example.com
- The "Set-Cookie" header looks like this:
EXAMPLE_SESSION_ID=55A66FFAB27931F115D9E6BA23A11EE4; Max-Age=7200; Expires=Sun, 08-Nov-2020 23:53:39 GMT; Domain=example.com; Path=/; Secure; HttpOnly; SameSite=None
- CORS Headers:
Access-Control-Allow-Origin: https://ui.example.com
Access-Control-Allow-Credentials: true
Can anyone help me figure out why the cookie is not being included in requests to the back-end after the page is refreshed?
Edit
Here is the code to configure CORS and Cookies.
Back-End CORS Configuration
@Bean
public CorsConfigurationSource corsConfigurationSource() {
CorsConfiguration corsConfiguration = new CorsConfiguration().applyPermitDefaultValues();
corsConfiguration.setAllowedOrigins(getAllowedOrigins());
corsConfiguration.setAllowCredentials(true);
corsConfiguration.setAllowedHeaders(
List.of(
"origin",
"content-type",
"accept",
"cookie",
"x-csrf-token"
)
);
corsConfiguration.setAllowedMethods(
List.of(
HttpMethod.OPTIONS.name(),
HttpMethod.GET.name(),
HttpMethod.POST.name(),
HttpMethod.PUT.name(),
HttpMethod.PATCH.name(),
HttpMethod.DELETE.name()
)
);
UrlBasedCorsConfigurationSource corsConfigSource = new UrlBasedCorsConfigurationSource();
corsConfigSource.registerCorsConfiguration("/**", corsConfiguration);
return corsConfigSource;
}
Back-End Cookie Customization
@Getter
@Value("${my.custom.property.session.cookie.domain:}")
private String customPropertyCookieDomain;
@Bean
public WebServerFactoryCustomizer<TomcatServletWebServerFactory> stackOverflowExampleWebServerCustomizer() {
return factory -> {
factory.addContextCustomizers(customizer -> {
Rfc6265CookieProcessor cookieProcessor = new Rfc6265CookieProcessor();
cookieProcessor.setSameSiteCookies("None");
customizer.setCookieProcessor(cookieProcessor);
if (StringUtils.isNotBlank(customPropertyCookieDomain)) {
customizer.setSessionCookieDomain(customPropertyCookieDomain);
}
});
};
}