Reputation: 4351
I would like to post using Axios
to my Spring Boot
server. If I disable csrf
using .csrf().disable()
it works correctly however it fails when enabled.
I've tried adding X-CSRF-TOKEN
to the header, or _csrf
in the body but it is saying it is invalid. Checking the request the csrf
is being passed in as expected.
CSRF Controller
@RequestMapping("/csrf")
public String csrf(final CsrfToken token) {
return token.getToken();
}
Spring Security
httpSecurity
.antMatcher("/api/**")
.cors().and()
.authorizeRequests()
.anyRequest().authenticated()
.and()
.sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS);
Axios
axios
.post(
`/api/doSomething`,
{ id: id, _csrf: csrf},
{
withCredentials: true,
headers: {
'X-CSRF-TOKEN': csrf
}
}
)
.then(response => {
resolve(response.data);
})
.catch(error => {
reject(error);
});
MetaTags react-meta-tags
store the CSRF
<MetaTags>
<meta name="csrf-token" content={csrfToken} />
</MetaTags>
Axios to get the CSRF token
axios
.get('/csrf', {
withCredentials: true
})
.then(response => {
resolve(response.data);
})
.catch(error => {
reject(error);
});
Function to get the CSRF token from the meta tags
function getCSRFFromPage(): string | null {
const element = document.querySelector("meta[name='csrf-token']");
if (element !== null) {
const csrf: string | null = element.getAttribute('content');
return csrf;
} else {
return null;
}
}
Error
Invalid CSRF token found for <url>
What could be causing this to fail?
Upvotes: 2
Views: 7258
Reputation: 44675
There are two possible causes.
First of all, the CSRF token endpoint should match the Spring Security configuration. In your example, you're using antMatcher("/api/**")
, but CSRF token endpoint is /csrf
. This should likely become /api/csrf
.
The second part is that the CSRF token changes after each request. You didn't show the code where you invoke getCSRFFromPage()
, but this should happen before each call you make. If not, then only the first call with that CSRF token will succeed. All consecutive calls will fail.
If you don't like making an additional call with each request, then you can use the CookieCsrfTokenRepository
:
httpSecurity
// ...
.csrfTokenRepository(CookieCsrfTokenRepository.withHttpOnlyFalse());
By doing so, each time you make a request, you'll get an XSRF-TOKEN
cookie containing the next CSRF token. This should be passed within the X-CSRF-TOKEN
or X-XSRF-TOKEN
header. Many libraries, including Axios do this out of the box, so you don't have to do anything else.
You can customize this behavior by configuring the xsrfHeaderName
or xsrfCookieName
properties (see Request Config).
Upvotes: 1