Skip to main content

Using the SAP Application Router with the SAP Cloud SDK

This guide will show you how to use the SAP Application Router together with the SAP Cloud SDK. You will learn how to secure your application and configure multi-tenancy for principal propagation with an SAP Cloud SDK-based application example powered by nestJS.

SAP Application Router

To enable multi-tenancy for your application, you should use the SAP Application Router. The application router's primary purpose is to be the single entry point of a microservice-based application and act as the application's reverse proxy.

Its responsibilities consist of dispatching requests to backend microservices, authenticating users, and serving static content. The application router checks if a given request has a valid JSON Web Token (JWT) when accessing a target service. If the request contains a valid JWT, the application router forwards the request to the target service; if the request does not contain a valid JWT, the user must authenticate. When using an Identity Provider (IdP) to authenticate, the request is redirected to the IdP where a user gets authenticated and then redirected back to the application router.

Application Router flowApplication Router flow

Application Router Setup

To deploy your application router in SAP BTP Cloud Foundry, you need to configure it first. Let's walk through the four files you need to use.

The xs-security.json file defines the security and deployment options for an application. With the below example, you enable the shared tenant-mode for your xsuaa instance, which you need to enable multi-tenancy.

{
"xsappname": "approuter-scaffold",
"tenant-mode": "shared"
}

In the xs-app.json, you specify to which backend service a request is forwarded to, and how this request has to be authenticated. You can optionally specify a specific identityProvider that is used for the authentication.

In the example below, you forward every request against the application router's / route to the backend destination's / route.

{
"welcomeFile": "index.html",
"routes": [
{
"source": "/",
"target": "/",
"destination": "approuter-scaffold"
}
]
}

In the package.json there is only one dependency, the application router module.

{
"name": "approuter",
"dependencies": {
"@sap/approuter": "*"
},
"scripts": {
"start": "node node_modules/@sap/approuter/approuter.js"
}
}

The manifest contains your application router, as well as environment variables which your application router needs for multi-tenancy. Under env, you need to specify the TENANT_HOST_PATTERN and destinations. The destinations are the destinations you use in your xs-app.json where you forward requests to. The TENANT_HOST_PATTERN is a regular expression that describes how a tenant name should be retrieved from the host. You also have to bind the xsuaa which you configured with your xs-security.json to the application router.

applications:
- name: approuter-scaffold-approuter
routes:
- route: approuter-scaffold-apps.cfapps.sap.hana.ondemand.com
path: .
memory: 128M
buildpacks:
- nodejs_buildpack
env:
TENANT_HOST_PATTERN: 'approuter-scaffold-(.*).cfapps.sap.hana.ondemand.com'
destinations: '[{"name":"approuter-scaffold","url":"approuter-scaffold.cfapps.sap.hana.ondemand.com","forwardAuthToken":true}]'
services:
- approuter-scaffold-xsuaa

Securing Your Application

Utilize the passport library to secure your application endpoints. It lets you authenticate endpoints using a JSON web token.

Additionally, the xsenv library can retrieve your xsuaa credentials and the xssec library's JWTStrategy object for the middleware.

Below is a simple example, where you get the approuter-scaffold-xsuaa which is bound to your application, use it in the JWTStrategy, and then forward the middleware to the passport.

import { NestFactory } from '@nestjs/core';
import { AppModule } from './app.module';
import { JWTStrategy } from '@sap/xssec';
import { getServices } from '@sap/xsenv';
import * as passport from 'passport';

const xsuaa = getServices({
xsuaa: { name: 'approuter-scaffold-xsuaa' }
}).xsuaa;
passport.use(new JWTStrategy(xsuaa));

async function bootstrap() {
const app = await NestFactory.create(AppModule);
app.use(passport.initialize());
app.use(passport.authenticate('JWT', { session: false }));
await app.listen(process.env.PORT || 3000);
}
bootstrap();

Enabling Principal Propagation

To enable principal propagation with this setup, you must forward the request to the endpoints.

First, you forward the request in your app.controller.ts to the principal propagation endpoint.

@Get('principal-business-partner')
getPrincipalBusinessPartner(
@Req() request: Request,
): Promise<BusinessPartner[]> {
return this.principalBusinessPartnerService.getFiveBusinessPartners(
request,
);
}

Then, you can use the SAP Cloud SDK's retrieveJwt() function to extract the JWT from your request, and forward it to the execute() method.

Below is an example using the BusinessPartnerService showing how to retrieve the top five business partners.

import { Injectable } from '@nestjs/common';
import { retrieveJwt } from '@sap-cloud-sdk/connectivity';
import { Request } from 'express';
import { businessPartnerService } from './generated/business-partner-service';

@Injectable()
export class PrincipalBusinessPartnerService {
async getFiveBusinessPartners(request: Request): Promise<BusinessPartner[]> {
return BusinessPartner.requestBuilder()
.getAll()
.top(5)
.execute({
destinationName: 'MY-DESTINATION',
jwt: retrieveJwt(request)
});
}
}