Search code examples
spring-securitycsrffetch-api

How to add the CSRF token to the HTTP header using fetch API and VanillaJS


I am trying to send a POST-request to a server that is configured to use Spring Security. When submitting my request, I get a 403 error. This is issue is due to CSRF protection. When disabling CSRF in my Spring Security Configuration, the POST request works fine.

I am using the fetch API to send my POST-request. This allows for specifying the HTTP-header that comes with the body containing my JSON-object that I am trying to POST. I am now trying to add the CSRF token to my HTTP-header. For this purpose, I have added the following two meta-tags to the head-section of my HTML:

<meta name="_csrf" content="${_csrf.token}"/>
<meta name="_csrf_header" content="${_csrf.headerName}"/>

I have then added the following lines to my JavaScript:

 const token = document.querySelector('meta[name="_csrf"]').content;
 const header = document.querySelector('meta[name="_csrf_header"]').content;

 let responsePromise = fetch(
     "myEndpoint",
     { method: 'POST', headers: {'Content-Type': 'application/json', header: token}, body: JSON.stringify(myJSON) });
    })

I am assuming that Spring Security fills out the content of my CSRF-token. So far the error message still persists though. I think there might be nothing inside my _csrf meta-tag. When logging the content (token and header), I just receive:

${_csrf.headerName}
${_csrf.token}

While I am expecting to see the header name "X-CSRF-Token" and the actual token. So could it be that Spring security does not automatically fill out this content?

======= Update:

My project is a Maven project. I have added the Thymeleaf-dependency to my pom.xml. I don't know much about thymeleaf, but it seemed to be the easiest way to implement the Login mechanism with Spring Security. Anyways, when replacing content with th:content in my meta-tags, the header and the token are actually found and will be logged in my console. I am still not able to POST my request though, the 403 remains.


Solution

  • Add 'th' before the attribute for thymeleaf processing

    <meta name="_csrf" th:content="${_csrf.token}"/>
    <meta name="_csrf_header" th:content="${_csrf.headerName}"/>