cancel
Showing results for 
Search instead for 
Did you mean: 
Read only

Custom Approuter - Frontend Backend Communication

SuperMario94
Discoverer
0 Likes
433

 

How to Restrict Backend Access to Frontend Only in SAP BTP (SAP UI5 + AppRouter + XSUAA)?

Hey everyone,

I’m currently working on an SAP UI5 application that is deployed via a Custom AppRouter. This app communicates with a backend service that extracts a specific user attribute (myspecialnumber) from the JWT token(we need that myspecialnumber to be displayed int the frontend). The authentication is handled via SAP XSUAA, and the users log in using our corporate Entra ID (Azure AD).

So far, everything works as expected:

Issue: Unrestricted Backend Access via Browser

Currently, any logged-in user can directly access the backend API by simply entering the URL in the browser:

👉 https://mybackend.cfapps.eu11.hana.ondemand.com/backend/userinfo

This means that users can bypass the frontend and call the backend API directly. However, I want to ensure that only my UI5 application can communicate with the backend, and anyone trying to access it manually (e.g., via the browser or Postman) should get a 403 Forbidden error.

How Can I Secure This?

How should we modify our architecture or security setup to achieve this? Any best practices or recommendations would be highly appreciated!

Below are my current configurations:


📌 xs-app.json (AppRouter Configuration)

{
  "welcomeFile": "/index.html",
  "routes": [
    {
      "source": "^/backend/(.*)$",
      "target": "/$1",
      "destination": "my-backend",
      "authenticationType": "xsuaa"
    },
    {
      "source": "^/(.*)$",
      "target": "$1",
      "localDir": "./webapp",
      "authenticationType": "xsuaa"
    }
  ]
}

📌 manifest.yaml (Deployment Configuration)

applications:
  - name: my-approuter
    memory: 128M
    buildpacks:
      - nodejs_buildpack
    command: npm start
    routes:
      - route: myapprouter.cfapps.eu11.hana.ondemand.com
    services:
      - xsuaa-myapprouter
    env:
      destinations: >
        [
          {
            "name": "my-backend",
            "url": "https://mybackend.cfapps.eu11.hana.ondemand.com",
            "forwardAuthToken": true
          }
        ]

📌 Node.js Backend Route (API Endpoint for User Info)

app.get('/userinfo', passport.authenticate('JWT', { session: false }), (req, res) => {
  console.log('GET /userinfo request received');
  const authHeader = req.headers.authorization;
  console.log('Authorization Header:', authHeader);

  if (!authHeader || !authHeader.startsWith('Bearer ')) {
    console.log('Invalid Authorization Header');
    return res.status(403).send('Invalid authorization header.');
  }

  const token = authHeader.split(' ')[1];
  console.log('Token:', token);

  xssec.createSecurityContext(token, uaaService, (error, securityContext) => {
    if (error) {
      console.error('Error processing token:', error.message);
      return res.status(403).send(`Token processing error: ${error.message}`);
    }

    const myspecialnumber = securityContext.getAttribute("myspecialnumber");  
    const userInfo = {
      email: securityContext.getEmail(),
      name: securityContext.getLogonName(),
      given_name: securityContext.getGivenName(),
      family_name: securityContext.getFamilyName(),
      myspecialnumber: myspecialnumber,
      token: token
    };

    console.log('User Info:', userInfo);
    res.json(userInfo);
  });
});

📌 UI5 Frontend Fetch Request

<!DOCTYPE html>
<html>
<head>
  <meta charset="UTF-8" />
  <title>MYApp</title>
  <script id="sap-ui-bootstrap" src="https://ui5.sap.com/resources/sap-ui-core.js"
    data-sap-ui-theme="sap_fiori_3"
    data-sap-ui-libs="sap.m"
    data-sap-ui-compatVersion="edge"
    data-sap-ui-async="true"
    data-sap-ui-resourceroots='{
      "myapp": "./"
    }'>
  </script>
  <script>
    function fetchUserInfo() {
      console.log('Fetching user info...');
      
      fetch('backend/userinfo', { method: 'GET' })
      .then(response => {
        console.log('Response received:', response);
        if (!response.ok) {
          throw new Error('Network response was not ok');
        }
        return response.json();
      })
      .then(data => {
        console.log('User info received:', data);
        document.getElementById('userInfo').innerText = `User: ${data.name} (${data.email})`;
      })
      .catch(error => {
        console.error('Error fetching user info:', error);
      });
    }

    sap.ui.getCore().attachInit(function () {
      console.log('SAP UI5 Core initialized');
      sap.ui.require(["sap/ui/core/ComponentContainer"], function (ComponentContainer) {
        console.log('Creating ComponentContainer...');
        new ComponentContainer({
          name: "myapp",
          height: "100%",
        }).placeAt("content");
        console.log('ComponentContainer placed at content');
      });
      
      fetchUserInfo();
    });
  </script>
</head>
<body class="sapUiBody">
  <div id="userInfo" style="padding: 10px; font-weight: bold;">Loading user information...</div>
  <div id="content"></div>
</body>
</html>

Accepted Solutions (0)

Answers (0)