Technology Blogs by Members
Explore a vibrant mix of technical expertise, industry insights, and tech buzz in member blogs covering SAP products, technology, and events. Get in the mix!
Showing results for 
Search instead for 
Did you mean: 
Active Participant



Hi Community,

The purpose of this blog is to share my learnings of cloud foundry destination service. I searched for blogs on multi-tenancy in cloud foundry destination service. I did not find one or I did not search enough?. So i did some further investigation and experimentation in this area and want to share my findings and learnings so that others looking for similar information can benefit out of it.

As we know, cloud foundry destination service is used to store service endpoints and credential details in a secure way that applications can use during runtime to connect to the services. Destination service is one of the service that inherently supports multi-tenancy. Let us understand multi-tenancy of destination service below.




Multitenancy logically starts at security as tenant level isolation is needed for access to the application. So in xs-security.json file “tenant-mode” is defined as “shared” and a scope “$XSAPPNAME.Callback” is defined for application to access saas-registry.

"xsappname": "cfdestination",
"tenant-mode": "shared",
"description": "Security profile of cfdestination app",
"scopes": [{
"name": "$XSAPPNAME.Callback",
"description": "With this scope set, the callbacks for tenant onboarding, offboarding and getDependencies can be called.",
"grant-as-authority-to-apps": [
"name": "$",
"description": "Read Scope"
"name": "uaa.user",
"description": "uaa.user"
"role-templates": [
"description":"Call callback-services of applications",
"name": "Viewer",
"description": "Viewer Role Template",
"scope-references": [
"role-collections": [
"name": "MyDestinationApplicationViewer",
"description": "My Destination Application Viewer",
"role-template-references": [


Implement rest endpoints for saas-registry:


Develop Node.js application with express and implement following endpoints for saas-registry


For tenant onboarding and offboarding.


For dependencies


Endpoint implementations:
router.get('/callback/v1.0/dependencies', dependencyCallbackRoute);
router.put('/callback/v1.0/tenants/*', subscribeTenantRoute);
router.delete('/callback/v1.0/tenants/*', unsubscribeTenantRoute);

export async function dependencyCallbackRoute(req: Request, res: Response) {
var dest = xsenv.getServices({ destination: { tag: 'destination' } }).destination;
var xsappname = dest.xsappname;
res.status(200).json([{'appId': xsappname, 'appName': 'destination'}]);

export async function subscribeTenantRoute(req: Request, res: Response) {
var consumerSubdomain = req.params["0"];
var tenantAppURL = "https:\/\/" + consumerSubdomain + "";

export async function unsubscribeTenantRoute(req: Request, res: Response) {


Implement endpoint for retrieving destination details:


Implement a custom endpoint that provides the destination details for the given destination name. SAP Cloud SDK getDestination() is used to fetch the cloud foundry destinations.

import { getDestination, DestinationOptions, DestinationSelectionStrategies } from '@sap-cloud-sdk/core';

router.get("/api/cloudfoundry/destinations", getCFDestinationsRoute);

let options: DestinationOptions = {}

export async function getCFDestinationsRoute(req: Request, res: Response) {
var paramdestination = req.query.destination;
options.selectionStrategy = DestinationSelectionStrategies.subscriberFirst;
options.userJwt = req.authInfo.getTokenInfo().getTokenValue();
var destination = await getDestination(paramdestination, options);
if (req.authInfo !== undefined && req.authInfo.checkLocalScope("read")) {
} else {
res.type("text/plain").status(401).send(`ERROR: Not Authorized. Missing Necessary scope`)



Implement Approuter:


Implement approuter that acts as single entry point to the application and takes care of user authentication.

"name": "cfdestinationui",
"version": "1.0.0",
"description": "UI Module for Destination Application",
"devDependencies": {
"@sap/grunt-sapui5module-bestpractice-build": "^0.0.14"
"dependencies": {
"@sap/approuter": "2.7.1"
"scripts": {
"start": "node node_modules/@sap/approuter/approuter.js"


Configure approuter in xs-app.json file as below:

"welcomeFile": "/cfdestinationui/index.html",
"authenticationMethod": "route",
"logout": {
"logoutEndpoint": "/logout"
"routes": [{
"source": "^/cfdestinationui/(.*)$",
"target": "$1",
"localDir": "webapp"
}, {
"source": "^/cfdestinationbackend/(.*)$",
"target": "$1",
"csrfProtection": true,
"authenticationType": "xsuaa",
"destination": "cfdestinationbackend_api"


Multi Target Application:


The application is built as multi target application with an mta.yaml file. It has two modules. cfdestinationbackend, a Node.js application and cfdestinationui, an approuter application. While other parts of mta.yaml is quite standard as with any mta deployments, I request your attention to  section TENANT_HOST_PATTERN which will help to identify the tenant information from the application url.

ID: cfdestinationapp
_schema-version: '2.1'
description: A multi-tenant enabled app for cf destination
version: 1.0.0


- name: cfdestinationbackend
type: nodejs
path: cfdestinationbackend
disk-quota: 512M
memory: 512M
- name: cfdestinationbackend_api
backend_app_url: '${default-url}'
- name: cfdestination-uaa
- name: cfdestination-destination
- clientid: "*"
identityzone: "*"

- name: cfdestinationui
type: html5
path: cfdestinationui
disk-quota: 512M
memory: 512M
builder: grunt
- name: cfdestination-uaa
- name: cfdestinationbackend_api
group: destinations
name: cfdestinationbackend_api
url: '~{backend_app_url}'
forwardAuthToken: true

- name: cfdestination-uaa
path: ./xs-security.json
service-plan: application

- name: cfdestination-destination
type: org.cloudfoundry.managed-service
service: destination
service-plan: lite


Deploy the Application to Cloud Foundry:


Once deployed, the below service instances created, and applications deployed.


Service Instances:




SaaS registry:


Configuration file for saas-registry service instance creation is shown below:

"appId": "cfdestination!t50911",
"displayName": "CF Destination App",
"description": "App to Demo CF Destination",
"category": "Demo Provider",
"appUrls": {
"onSubscription": "{tenantId}",
"getDependencies": ""


Get XSAPPNAME from VCAP_SERVICES.xsuaa.credentials.xsappname (here cfdestination!t50911)

Get the onSubscription and getDependencies URL from backend application.


Create Saas registry service instance:

cf cs saas-registry application cf-destination-registry -c config.json


Bind the backend app to the SaaS registry service instance:

cf bs cfdestinationbackend cf-destination-registry


Re-stage the app by executing this command:

cf restage cfdestinationbackend


Testing in Provider Tenant:


Create destination named “mydestination” at subaccount level as shown



Calling the API with destination name (/api/cloudfoundry/destinations?destination=mydestination) retrieves the details of destination.



Now a destination with same name “mydestination” is created in the Destination service instance.



Calling the API (/api/cloudfoundry/destinations?destination=mydestination) retrieves the details of destination from destination service instance. The SAP Cloud SDK gives preference to the destination in service instance over subaccount and provides the destination details form service instance.



Onboard a subscriber tenant:


Create a Cloud Foundry subaccount for the application consumer (tenant).



Now additional subaccount just created is seen in the global account screen



Navigate to the new consumer subaccount and to the Subscriptions tab. The CF Destination App is seen under the Demo Provider category.



Subscribe to the Application:



Upon successful subscription, the status shows subscribed:



Create a new route for the newly subscribed tenant and assign to the approuter/ ui application:




Subscriber subaccount Test:


Access the application using subaccount specific route

Once login, call the api endpoint

Accessing the API will still give the destination details from the destination service instance.




Now create a destination in subscriber subaccount “mytenant1” with same name “mydestination”.



Calling the api again, will provide the destination details of “mytenant1” subaccount. The SAP Cloud SDK gives preference to subscriber subaccount destinations over provider subaccount destinations.




Destination service of cloud foundry is a multitenant service and the multitenant capabilities can be leveraged with sap cloud sdk. The sample application shown in this blog is shared in github repo.

There are other blogs on working with destination service in CAP and Node.js and I provided some great references in the references section. I hope you got as much fun reading this blog as I did writing this. I would love to hear your comments and feedback.

Thank you and have a great day…



Use SCP CF Destination service in NodeJs locally by Wouter Lemaire

CAP: Consume External Service – Part 1 by Jhodel Cailan

Call SAP Cloud Platform destinations from your Node.js application by Maria Trinidad MARTINEZ GEA

Consuming destinations in cloud foundry using axios in a nodejs application by Joachim Van Praet

Multitenancy Architecture on SAP Cloud Platform, Cloud Foundry environment by Jan Rumig

Using SaaS Provisioning Service to develop Multitenant application on SAP Cloud Platform, Cloud Foundry Environment by SANDEEP TDS

Developing Multitenant Applications on SAP Cloud Platform, Cloud Foundry environment by Hariprasauth R

SAP Cloud SDK for JS




Labels in this area