Describe the bug After implementing CSRF protection for SPAs following Spring's official guide, where it's stated that "Refreshing the token after authentication success and logout success is required because the CsrfAuthenticationStrategy and CsrfLogoutHandler will clear the previous token. The client application will not be able to perform an unsafe HTTP request, such as a POST, without obtaining a fresh token." I have noticed that the CSRF token is not cleared by the CsrfAuthenticationStrategy after successful authentication.

To Reproduce Step 1. Submit POST request for authentication (I'm using Postman) to endpoint with no cookies present and without X-XSRF-TOKEN header. Result is 403 Forbidden status and a new cookie received with the CSRF Token. Step 2. Add the X-XSRF-TOKEN header with the CSRF Token received in the cookie and send POST request again. Result is successful authentication and 200 OK status. Step 3. Submit another POST request (In my case I'm using a different endpoint too) with the same CRSF token value. Result is 200 OK status and a state changing action passed through.

Expected behavior According to the Spring guide, on step 3 the result should be 401 or 403 status due to the first CSRF token being cleared after successful authentication.

Sample

A link to a GitHub repository with a minimal, reproducible sample. In the sample I have prepared, all that's needed is a MySQL DB with a security_sample schema and to add the spring data source username, password, and url in application.yalm. Endpoints for testing are available in Controller class. Step 1 and 2 tested on /login endpoint and step 3 on /{role} endpoint. A user with "user" username and "password" will be automatically created and ready for /login endpoint. I have used the following: DATABASE_URL=jdbc:mysql://localhost:3306/security_sample?useSSL=FALSE&allowPublicKeyRetrieval=true&serverTimezone=UTC DATABASE_USERNAME=root DATABASE_PASSWORD=mysql password

Comment From: sjohnr

@Claudius10, thanks for the sample! However, you mention that MySQL is required to run the sample, which is not minimal. Could you kindly update the sample by removing MySQL and JPA entities so that only the minimal code to reproduce the issue is present in the sample?

Comment From: Claudius10

Yes of course, I've removed the JPA and MySQL dependencies and used the InMemoryUserDetailsManager instead. All is needed now is to run the sample and follow the steps to reproduce. For step 1 the end point is auth/login with a json body of username/password, and for step 3 the endpoint is auth/post.

Comment From: sjohnr

@Claudius10, I have reviewed and tested your sample and found that you have implemented a custom authentication endpoint which does not work like Spring Security's authentication filters (such as UsernamePasswordAuthenticationFilter enabled via http.formLogin()). You should either use a built-in authentication filter or provide integration with the needed Spring Security components (such as CsrfAuthenticationStrategy) yourself (though this isn't usually recommended).

The CSRF page of the reference documentation you mentioned links to the Authentication section of the docs and additionally comes after that section in the navigation/ToC because understanding the authentication mechanism(s) of the framework is requisite reading prior to CSRF protection and/or implementing custom authentication mechanisms.

I'm going to close this issue based on the above explanation. If you have any further questions, please feel free to link to a stackoverflow question and I'll be happy to take a look.