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:
- disable for http-client
- disable for v2 OData clients
- disable for v4 OData clients
- disable for OpenAPI clients
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:
- disable for http-client
- disable for v2 OData clients
- disable for v4 OData clients
- disable OpenApi clients.
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.