When an API is secured against CSRF attacks, we must ensure that our clients’ requests are adjusted to the security requirements. Learn how to successfully call an API that uses the Cookie-to-header token approach by adding the X-XSRF-TOKEN header to Postman requests.
We get the Invalid CSRF token
error when an API has csrf protection enabled and our request doesn’t contain the required data. The security configuration regarding the csrf protection in my example Spring Boot project looks like this:
public static void configureApiSecurity(HttpSecurity http) throws Exception {
http
.csrf().csrfTokenRepository(CookieCsrfTokenRepository.withHttpOnlyFalse())
…
The Spring documentation describes the CookieCsrfTokenRepository
as follows:
A CsrfTokenRepository that persists the CSRF token in a cookie named “XSRF-TOKEN” and reads from the header “X-XSRF-TOKEN”
https://docs.spring.io/spring-security/site/docs/5.0.13.RELEASE/api/index.html?org/springframework/security/web/csrf/CookieCsrfTokenRepository.html
As a result, the token will be present in the API responses as seen in the screenshot below:
Consequently, when I’m sending a POST request with no value provided in the required header, I get the 403 Forbidden in response. The exact error is specified in the application logs:
DEBUG 11528 --- [nio-8080-exec-3] o.s.security.web.csrf.CsrfFilter : Invalid CSRF token found for http://localhost:8080/api/products
DEBUG 11528 --- [nio-8080-exec-3] o.s.s.w.access.AccessDeniedHandlerImpl : Responding with 403 status code
In a Spring Boot application, we can debug the actual value that is checked in the CsrfFilter class:
In my case, the actual value is null. So I need to add the X-XSRF-TOKEN header to my Postman POST requests.
I’m going to configure my Postman collection to get the current token from each request and save it as an environment variable. Then, I will use this variable as the header value for my POST calls.
To read the value of the cookie, we’re going to execute a short JavaScript code in Postman.
The sample collection I’m using for this article is in my public Postman workspace and is part of my keycloak-spring-boot
project. If you want to test my code locally (it requires Docker for running a Keycloak instance), visit the project repository on GitHub and follow the directions in the README.md file.
First, I’m going to place the js code in the Collection testing space. As we can read in the documentation:
A test script associated with a collection will run after every request in the collection.
https://learning.postman.com/docs/writing-scripts/test-scripts/#testing-collections-and-folders
This way, I won’t have to add the script to every POST request I may create in this collection in the future.
I’m going to edit my example keycloak-spring-boot
collection:
Then, I’m going to add the following code to the Tests
tab:
var xsrfCookie = pm.cookies.get("XSRF-TOKEN");
pm.environment.set('xsrf-token', xsrfCookie);
You can see the result in the screenshot below:
Finally, I’m going to save the changes to the collection by clicking the Update
button.
Alternatively, I can only read the cookie after a selected request. To achieve this, I will need to add the js code in the request-specific test space and click the Save
button. In summary, the configuration of a single request will look like this:
In this case, we must remember to add the js code to any future POST request as well.
First, I’m going to verify that the value is actually available as an environment variable in Postman after running my request. Therefore, I’m going to execute the request, click on the Environment quick look
button (the eye icon) and look for the xsrf-token
variable as shown in the screenshot below:
Now I’m going to add a new header to my request, with the following data:
X-XSRF-TOKEN
,{{xsrf-token}}
.We can see the result in the screenshot below:
Finally, I can make my POST request with the certainty that it will work successfully:
What to check when API calls don’t work as planned?
{{xsrf-token}}
variable set in Postman environment? You can see its current value in the Environment quick look
or by hovering over the variable. Select the proper environment (localhost
in my example) and make sure that the value is not empty.Photo by Andrea Piacquadio from Pexels
Spring Security allows us to use role-based control to restrict access to API resources. However,…
A custom annotation in Spring Boot tests is an easy and flexible way to provide…
Delegating user management to Keycloak allows us to better focus on meeting the business needs…
Swagger offers various methods to authorize requests to our Keycloak secured API. I'll show you…
Configuring our Spring Boot API to use Keycloak as an authentication and authorization server can…
Keycloak provides simple integration with Spring applications. As a result, we can easily configure our…
View Comments
what option to choose under 'Authorization'?
I think it depends on the security configuration of the API you're trying to call.
To test adding the token in Postman to call an API secured with Basic Auth:
clone the spring-boot-swagger-ui-basic-auth project and run the app locally;
select the
Basic Auth
Authorization Type and provide username and password (from the project's README.md);follow the steps described in this article to add the token;
if the configuration works, the app returns
204 No Content
response on the DELETE endpoint.Below is a screenshot from my Postman:
Thanks, this article solved my problem.
Glad to have helped :)