cancel
Showing results for 
Search instead for 
Did you mean: 

SAP BTP React app - CSRF token validation failed - during POST to Public Cloud

04-16-2025 4:21 PM
LaurensSteffers Participant
2323 views 1 comments Go to solution
0 Likes
SAP Managed Tags
Labels
BTP DestinationCSRF TokenReactJS
Subscribe

Hi all,

I'm a little but stuck. Hope you can help, here is the case:

I'm currently working on a application which fetches data from the backend, and posts new entries to custom business object using API calls. 

I've wrote the application in React, using SAP BAS to deploy it to SAP BTP on CF. 

I use the xsuaa service, bind it to my app, and have login feature to start the application.

I use a destination service and connect it through the destination to S4Hana Public Cloud with the comm user (yes, I tried oauth2samlbearer but somehow I can't get it to work (anyone got a guide? 😉 ) ). It is bound to the service.

When I fetch data, all works fine, it fetches process order information.

I do some stuff with the orders, and the results should be send to S4Hana Public cloud, to a business object which is exposed. 

So I fetch the X-CSRF-Token (is getting fetched), pass this to the post including payload, and.....it fails with the 403 error that my csrf token validation failed. 

The things I checked already:

The authentication is always set to true, so the cookie handling should be done by the browser:

const getAxiosConfig = () => { return { withCredentials: true, }; };

When I try to do this manually (getting the cookies and combining them), the cookies are not exposed do to security reason. Pretty sure it is not advised to do so btw

export const createProcessOrderSet = async (payload) => {
  const local = "/sap/opu/odata/sap/YY1_PROCESSORDERS_CDS/YY1_PROCESSORDERS";
  const destination = "/destination/S4H_BACKEND/sap/opu/odata/sap/YY1_PROCESSORDERS_CDS/YY1_PROCESSORDERS";
  const url = process.env.NODE_ENV === "production" ? destination : local;
  const config = { withCredentials: true };

  // Log URL for debugging
  console.log("Using URL:", url);

  try {
    // Fetch CSRF token via GET request
    const csrfResponse = await axios.get(`${url}?$top=1`, {
      ...config,
      headers: {
        "X-CSRF-Token": "Fetch",
        Accept: "application/json",
      },
    });

    // Retrieve CSRF token using both lower and proper case header names
    const csrfToken = csrfResponse.headers["x-csrf-token"] || csrfResponse.headers["X-Csrf-Token"];
    if (!csrfToken) {
      throw new Error("CSRF Token not received from SAP");
    }
    console.log("CSRF Token:", csrfToken);

    // Rely on the browser's cookie management (withCredentials) for session cookies
    // No manual Cookie header is set here.

    // Perform the POST request using the CSRF token
    const postResponse = await axios.post(url, payload, {
      ...config,
      headers: {
        "X-CSRF-Token": csrfToken,
        "Content-Type": "application/json",
        "Accept": "application/json",
      },
    });

    return postResponse.data;
  } catch (error) {
    console.error(" Error creating process order set:", error);
    throw error;
  }
};

When I do all this locally using a proxy in my app, the posting and stuff just works fine. It looks like the destination is the issue I think, but even that is not something unfamiliar. Any hints or tips regarding the destination or the destination services? I searched of course but notes and hints are mostly targeted at onprem/private cloud. The manual cookies didn't work, no authentication didn't work, the only difference is the destination, but the fetch of data (standard api's) do work, except for the post.

Anything would help 🙂

Cheers!

Laurens

 

 

 

 

0 Likes

Accepted Solutions (1)

Accepted Solutions (1)

LaurensSteffers
Participant
0 Likes

Yes! Fixed the issue, thanks to my fantastic colleague in the UK.

The issue is that the approuter handles the csrf token stuff, but we request it from the backend. So using this (csrfProtection:false), did the trick. Not easy to find if you never dealt with it:

{ "source": "^/destination/S4H_API/(.*)$", "target": "$1", "destination": "S4H_API", "authenticationType": "XSUAA", "csrfProtection": false }

 

Cheers!

Laurens

 

 

Answers (0)