Skip to main content

CSRF Fetching

Default Behaviour

The SAP Cloud SDK fetches a CSRF token for non GET requests by default. This is done for all clients that the SAP Cloud SDK provides:

If the target system does not require a token you can disable the fetching as discussed in the sections:

In order to retrieve a token the SAP cloud SDK makes multiple calls. First it makes a request using the resource URL adding a / in the end:

Request:             HEAD /resource/path/
Request Header: X-CSRF-Token=fetch

If this returns a token, execute the request with the token. If not, make a second call without the /:

Request:             HEAD /resource/path
Request Header: X-CSRF-Token=fetch

If this returns a token, execute the request with the token. If this also does not yield a token, the request is executed without an additional token. Note that the SAP Cloud SDK consider SET-COOKIE headers provided the requests returning the tokens.

Most systems will return a CSRF token independent of an additional / in the end. However, we saw issues for SAP S/4HANA OnPremise systems which required the / and other systems not being able to handle the slash. If performance is relevant you should check:

  • Does the system need a CSRF token? If not disable the fetching.
  • Does the system fail to return a CSRF with a /? Adjust the token fetching via a middleware.

Changing the Default

If the way the SAP Cloud SDK fetches the CSRF token does not fit your needs you can replace the default using a middleware. The SAP Cloud SDK offers a default implementation which allows minor adjustments as described here:

In this section you will learn how to implement a custom middleware which does only a single request without a slash. We will use the OData client for illustration but everything applies to the other clients as well. You disable the token fetching and add a middleware:

const { businessPartnerApi } = businessPartnerService();
businessPartnerApi
.requestBuilder()
.update(businessPartner)
.middleware([customCsrf])
.skipCsrfTokenFetching();

function customCsrf(options: HttpMiddlewareOptions) {
return requestConfig => {
const csrfToken = ''; //add your logic
requestConfig.headers['x-csrf-token'] = csrfToken;
options.fn(requestConfig);
};
}

A basic implementation for fetching a token using a single request without a slash in the end could look like:

function customCsrf(options: HttpMiddlewareOptions) {
return async requestConfig => {
const requestConfigCsrf = {
method: 'head',
headers: {
...requestConfig.headers, //Authentication headers are in here
'x-csrf-token': 'Fetch',
'content-length': 0
},
url: requestConfig.url.replace(/\/$/, '')
};

const response = await axios.request(requestConfigCsrf);

requestConfig.headers['x-csrf-token'] = response.headers['x-csrf-token'];

return options.fn(requestConfig);
};
}

This implementation is meant as an example to illustrate the concept. It misses many things like setting cookies provided by the first request or checking the request method.