-
Notifications
You must be signed in to change notification settings - Fork 5.9k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
CSRF example for Single-Page Apps could be improved #15105
Comments
@jarekkar thank you for providing feedback on the current documentation so that we can improve it!
The sample code in the comment is a variation on the code provided in the docs. In order to proceed and find the best enhancement to the docs, can you please describe in more detail the issues you encountered following the current recommendation in the docs?
I am not aware of any specific issues with the example working with OAuth2 Login. Can you please clarify what issues you encountered or provide a sample that demonstrates? |
@sjohnr @jarekkar I'd like to highlight that there's an issue with the CSRF protection for Single Page Applications (SPA) official documentation, as outlined in this issue. Exercise care before using/implementing it. |
@sjohnr Here is my setup: @Configuration(proxyBeanMethods = false)
class SecurityConfig {
@Order(1)
@Bean
SecurityFilterChain authenticatedFilterChain(
HttpSecurity http,
ClientRegistrationRepository clientRegistrationRepository
) throws Exception {
String[] all = {
"/oauth2/authorization/app",
"/login/oauth2/code/app",
"/account"
};
DefaultOAuth2AuthorizationRequestResolver resolver = new DefaultOAuth2AuthorizationRequestResolver(
clientRegistrationRepository,
DEFAULT_AUTHORIZATION_REQUEST_BASE_URI
);
resolver.setAuthorizationRequestCustomizer(OAuth2AuthorizationRequestCustomizers.withPkce());
http
.securityMatcher(all)
.csrf(csrf -> {
csrf.csrfTokenRepository(CookieCsrfTokenRepository.withHttpOnlyFalse());
csrf.csrfTokenRequestHandler(new SpaCsrfTokenRequestHandler());
})
.addFilterAfter(new CsrfCookieFilter(), BasicAuthenticationFilter.class)
.sessionManagement(session -> {
session.sessionCreationPolicy(ALWAYS);
})
.authorizeHttpRequests(auth -> auth.anyRequest().authenticated())
.oauth2Login(oauth2 -> {
oauth2.authorizationEndpoint(endpoint -> {
endpoint.authorizationRequestResolver(resolver);
endpoint.authorizationRequestRepository(new HttpSessionOAuth2AuthorizationRequestRepository());
});
oauth2.successHandler(new SimpleUrlAuthenticationSuccessHandler("https://my-domain/home"));
})
.exceptionHandling(
exception -> exception.authenticationEntryPoint(new HttpStatusEntryPoint(UNAUTHORIZED))
);
return http.build();
}
final class CsrfCookieFilter extends OncePerRequestFilter {
@Override
protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response,
FilterChain filterChain)
throws ServletException, IOException {
CsrfToken csrfToken = (CsrfToken) request.getAttribute("_csrf");
csrfToken.getToken();
filterChain.doFilter(request, response);
}
}
}
Key urls:
Flow:
I would expect that service (in response in step 4.) stores XSRF-TOKEN cookie in the browser, so next request, e.g. POST /accounts can be protected with CSRF token. Unfortunately cookie is not stored so I started digging on how to enable such behaviour. I tested it with EntraID (Azure AD) and Okta. |
That issue was just closed as invalid. Please see this comment.
Thanks for providing additional details including your configuration! I now believe I understand the issue you're having. The documentation example recommends providing a In the case of an external redirect, you would first want to allow the entire filter chain to be executed. This can be achieved by redirecting to a Spring MVC There are numerous other ways to handle this situation, depending on preference and other considerations, but it's difficult to anticipate or capture all of those in reference documentation. I worry that covering too many specific scenarios involving frontend view technologies will overwhelm readers. Using a If you don't mind, I'd like to repurpose this ticket to address that in the documentation. |
Expected Behavior
Please provide a description in the documentation on how to properly set up CSRF protection with SPA and OAuth2Login.
Current Behavior
The current documentation (version 6.2.4) provides a description for BasicAuthentication: https://docs.spring.io/spring-security/reference/servlet/exploits/csrf.html#csrf-integration-javascript-spa
Context
The solution described in the documentation does save the XSRF-TOKEN cookie after authentication. I have tried several approaches on my own, but they did not work consistently. I found a solution in this comment: #14149 (comment), and it works. However, I am unsure if this is the recommended approach.
Could you please provide an official description in the documentation (and as a response to that issue) on how to properly adjust the described solution to work well with OAuth2Login?
The text was updated successfully, but these errors were encountered: