Skip to Content
Product Information

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

In the context of Cloud Computing, Multitenancy allows an application provider to serve applications and services to multiple tenants – a set of users. End users of the application access it through a URL dedicated to that tenant.

A tenant-aware application has the capability to separate data securely per tenant, can share resources across the tenants, and can serve features from a single code repository.

This blog elaborates on the process to build a multitenant application on SAP Cloud Platform in the Cloud Foundry environment. For multitenancy on the Neo environment, please see this blog.

Understanding Software as a Service (SaaS) Provisioning service

In the SAP Cloud Platform Cloud Foundry environment service marketplace, we can see SaaS Provisioning service as shown in the image below.

To make our SaaS Application available to multiple tenants we must set up a registry for our application. The SaaS Provisioning service is where we, as a SaaS Application provider, register our app. The SaaS Provisioning service enables us to automate the subscription process. It also maintains a list of all dependencies and subscriptions of an application.

A SaaS Application provider creates a subaccount to deploy the application. Inside this subaccount, the provider creates a space and deploys the SaaS Application. The provider then registers the application with a SaaS registry. The SaaS registry service on SAP Cloud Platform creates a new entry. Through this service, any sub-account, within the same global account, will see an entry of the provider application in the subscriptions tiles. The consumer then can subscribe to the application by just a click of a button. Each subaccount has a unique subdomain and identity zone id.


Understanding the concept through an example

Let’s look at how one can use SaaS Provisioning service to build a simple ‘Hello World’ multitenant application.

There is a SaaS Application provider – Provider ZZZ. Provider ZZZ would like to build an application that displays a hello message. The hello message will display the logged in user’s name and the tenant from which the user has logged in – as shown in the image


As ZZZ, we will build a ‘Hello World’ application to display the ‘hello message’. Also, since each tenant will access the application from a unique URL, we will build an app router app to resolve the URL, authorize the request and forward the request to our application.

Overview of the Steps Involved

1.     Develop A SaaS Application

In our application’s default end-point (GET – ‘/’) we will return a hello statement displaying the username, tenant subdomain, and tenant identity zone.

We deploy this application on our (provider’s) sub-account and test the application. Once we are satisfied with the development, we add the configurations required to make our application available across tenants.


2.     Add Configurations For Multitenancy

To make our application available to SaaS Provisioning service and to automate the subscription process we must add the following configuration to our SaaS Application.

The SaaS Provisioning service requires us to define the following API end-points.

  • PUT – ‘callback/v1.0/tenants/*
    • To onboard a tenant, i.e. when a consumer subscribes to the application
  • DELETE – ‘callback/v1.0/tenants/*’
    • To off-board a tenant, i.e. when a consumer unsubscribes to the application

Each consumer accesses the SaaS Application through a unique URL. To ensure that these requests come to the target application, we define a tenant host pattern for our app router app in the MTA.yaml file. Click here for the detailed documentation.

We specify the SaaS Application name, description, app category while creating a SaaS Provisioning service instance. We mention these details in a config.json


  "appId": "<XS-App Name>",

  "displayName": "Hello World",

  "description": "A sample hello world app to explain the concepts of Multitenancy",

  "category": "Provider ZZZ",

  "appUrls": {

    "onSubscription": "<Your back-end app URL>/callback/v1.0/tenants/{tenantId}"




3.     Register the SaaS Application to SaaS Provisioning

Upon completing our configuration, we create a SaaS Provisioning service and bind it to our SaaS Application. To complete this set of actions we require Cloud Foundry Command Line Interface.

We start this process by creating a new SaaS Provisioning service instance.

cf cs saas-registry application <Service name> -c <Path to config.js file>

Next, we bind our SaaS Application to the newly created SaaS Provisioning service instance.

cf bs <SaaS Provider Application Name> <SaaS Provisioning Service Name>

Once we bind our application to this service instance we will be prompted to restage our application. To do so, we execute the following command.

cf restage mt-hw-node-app


4.     Subscription of the SaaS Application by a Consumer

A consumer can subscribe to the application either through the SAP Cloud Platform Cockpit or through REST APIs.

Subscription through SAP Cloud Platform Cockpit

In your global account, create a new subaccount and go to the Subscriptions tab. The SaaS registry service shows the applications that have been registered with it. Here, you will find the provider’s application.

Click on the application tile and click on the subscribe button.

Subscription through REST APIs

You will require a client that can make REST API calls (such as Postman).

We first get the application authorization token. Using your Cloud Foundry Command Line Interface tool execute the following command

cf env <Name Of You SaaS App>

Create a new request in your client with the following setup. Copy the corresponding values from the environment variables.

HTTP Method – POST

URL – <"System-Provided"."VCAP_Services"."saas-registry"."credentials"."url">


Key: grant_type

Value: client_credentials

Authentication Type – Basic Authentication

Username - <"System-Provided"."VCAP_Services"."saas-registry"."credentials"."clientId">

Password - <"System-Provided"."VCAP_Services"."saas-registry"."credentials"."clientSecret">

You will receive the following as a response.


  "access_token": "xxxxxx",

  "token_type": "bearer",

  "expires_in": 43199,

  "scope": "yyyyyy",

  "jti": "zzzzz"


We use the access_token returned to call the subscription API in the next step.

HTTP Method – PUT

URL - <"System-Provided"."VCAP_Services"."saas-registry"."credentials"."tenant_onboarding_url">/api/v2.0/subscription/tenants/{tenantId}

tenantId – Tenant Zone Identity


Key: jobUuid

Value: A newly generated GUID

Authentication Type – OAuth 2.0

Access Token – Access token copied from the response of the earlier API

In upcoming blogs, we will take a look at the different APIs that can be used.


5.     Mapping Consumers’ Routes

In the last step, the provider needs to add a new route to ensure that a consumer’s request goes to the app router.

You can now launch the app for the consumer

In upcoming blogs, we will take a closer look at methods that we can adopt to automate the process of route mapping.



Please find the code for a ‘Hello World’ sample application here. This application has been developed using node.js. For further information and a step by step guide, please go through the Readme.MD file. If you prefer a video, please check out this playlist by SAP HANA Academy.


Now that you have an understanding of SaaS Provisioning and steps involved in building a multitenant application you can go through this blog to see how can we achieve multitenancy at persistence layer through SAP Cloud Platform, Cloud Foundry environment. The blog explains the concepts through a sample product inventory management application. To gain a deeper understanding of the architecture please read this blog.

You must be Logged on to comment or reply to a post.
  • Why is it necessary for tenant to be in the same global account as the provider when we use saas registry? Is there a config mode that needs to be changed to allow subscription of tenants from other global accounts?

  • Hi Sandeep,

    Are we supposed to add the route tenantId+appurl  to access the app? in my case, I have done this way but while trying to access the Tenant ID in the subscriber application, I'm getting tenant ID of the dev space where app deployed.

    I'm not sure if this is because of the app route that I have created after SaaS subscription or anything missing while provisioning/subscribing the app.


    Best regards,


    • Hi Gopal,

      Thank you for your question.

      You are expected to add construct your onSubscription URL in the following format:

      var tenantAppURL = "https:\/\/" + <subdomain name of the consumer+ <name of your application+ "<CF App Domain>";

      Please note that this is required only for those services which have to be multi-tenant. You need not do this for the app-router application.

      For code specific details please refer to the sample app included in the blog.

      I hope this answers your query.


    Thanks for the post.

    How would you implement a similar approach for a Fiori Launchpad module with some HTML5 applications (for apps built using Fiori Elements template) consuming odata? 

    Best regards,


    • Hi Andre,

      Thank you so much for the question.

      In case of an HTML5 Fiori application, you could use your UI app as the App Router.

      We have built a sample application for the same. You can access the same by using the following link:

      I hope this link helps you.

      • Hi SANDEEP TDS / Jan Rumig

        When creating an MTA with SAP Fiori Launchpad Module, the WebIDE generates the Approuter module. Which module should be used as the App Router : the Fiori Launchpad module or the App Router created by the WebIDE?



        • With Portal service 2.0 the Portal service is bound as a service to the approuter application running in CF. The Fiori Launchpad module is actually a deployer application that upload FLP content into the Portal service (e.g.: tiles configuration).

          Applications routing is supported by the approuter application. Running FLP is achieved by running a url with the following pattern:


          Note that the approuter url host may be dynamic in case of multitenant approuter.

          Best Regards


          • Thanks for the information, Sergio Rozenszajn !

            I am trying to build a multitenant app. When creating the app in a dedicated tenant mode, the app works fine. Portal gets launched with https://<approuter-url>/cp.portal/

            But when the same app is deployed as a multitenant app, the portal url shows the message "Internal Server Error"

            The app subscription from a tenant is successful. I am even able to access backend_api routes via the Approuter.

            Here is a sample xs-app.json file for the Approuter:

            	"welcomeFile": "/cp.portal",
            	"authenticationMethod": "route",
            	"logout": {
            		"logoutEndpoint": "/do/logout"
            	"routes": [{
            		"source": "^/callback/(.*)",
            		"target": "/callback/$1",
            		"destination": "backend_api"
            	}, {
            		"source": "^/be/(.*)",
            		"target": "$1",
            		"destination": "backend_api"


            Any thoughts on this?



          • Hi Ashish

            have you solved this problem? I’m encountering the same issue.

            The logs show the following error message:

            GET request to /cp.portal/site completed with status 500 - Call to /oauth/token was not successful (grant_type: user_token). Bearer token invalid, requesting client does not have grant_type=user_token or no scopes were granted.

            I have already assigned the scope uaa.user to the user in consumer and provider account.


          • Hi Simon,

            In my case, there was an issue with the subscription which was fixed by the SAP support team. I had logged a ticket with SAP.

            The error you are seeing looks different. If you are sure to have followed the role collection assignments for the subscribers as well, I would suggest you to log a ticket with SAP.

            - Ashish

    • Hi @andrefernandescontax,

      Did you implement the Fiori Launchpad module approach? Was this approach similar to this guide or were there some changes involved?




      • Hi Ashish,


        I am facing a similar issue as yours. i am getting the following error on accessing /cp.portal from subscriber account. Did you solve the issue?

        @Sergio Rozenszajn Do you have any idea on this?

        "GET request to /cp.portal/site completed with status 500 - Call to /oauth/token
         was not successful (grant_type: user_token). Bearer token invalid, requesting client does not have grant_type=user_token or no scopes were granted."
        • Hi Tapishnu,

          The error you are seeing points to a missing Authorisation step for the subscriber user. I think it should go away if proper steps are followed.

          – Ashish

  • Hi Sandeep,

    Little question about this topic can we use any language for this or only using javascript?
    If I have an application develop for example in ruby, can I deploy it ? Can we use container that contain the application ?

    Thanks for your help

    • Hi Emmanuel,

      Thank you so much for the question.

      No, you are not limited to Javascript. You can use Java, Python or other languages supported by the Cloud Foundry Community Buildpack.

      Irrespective of your development technologies, you must ensure that your application defines the required callbacks (See Step 2 of this Blog).

      You must architect your application in a way which allows you to define the callbacks and bind SaaS Provisioning Service.I hope this answers your query.

  • Hi Sandeep


    I have a new cloud platform (enterprise version) and this is the first thing I have done in it. I have not installed a HANA database as yet. I have picked up the cloud foundry endpoint from the Cloud Foundry subaccount in the box on the right hand side detailing the organisation, spaces, members and API endpoint (Sydney data centre:

    The app builds and deploys successfully, but when I try to launch it, I get redirected to a SAP HANA XS Advanced logon page. If I use my cloud platform credentials, it does not work.

    Is there something I need to do to my user or do I need to create a role for this to work?




    • Hi Neil,

      Thank you so much for your query.

      I am really glad that you are using SAP CP and were successfully able to deploy the application.

      Coming to your query, this happens because of the Tenant Host Pattern we define in our MTA.yaml file.

      Can you please try to create a new route that complies with the following pattern:

      https://<sub-account sub domain>-<app name>.<cf app url>

      For further details please refer to the guide here

      • Hi Sandeep

        Thanks for your response. Your response appear to apply to creating a route manually after the app has been subscribed too.

        Unfortunately, the XSA login screen appears for me after completion of step 4. Does this mean I have the tenant url in Step 3 incorrect?



        • Hi Neil,

          I apologize for the delay in my response.

          When we define a Tenant Host Pattern in our MTA.yaml file, as we have done in this application, our application routes and URL must conform to this pattern.

          Your current application URL, for the provider sub-account, should look something like this:

          https://<org-name>-<sub-accountName>-<space>-<appName>.<cf-app url>

          This route doesn't comply with the tenant-host pattern defined by us in the MTA.yaml file.

          Thus, to access the provider's application, you must create a route which matches the host pattern defined by us.


          For further understanding, you can remove the Tenant-Host Pattern and make other required changes (change UAA service to dedicated in xs-security.json) and deploy the application. When you do this, you will be able to access the application using the default URL constructed by the platform.

  • Hi Sandeep,

    While I am trying to delete the SaaS-registry instance, it throws the following error:

    Service instance pci-registry: Service broker error: SaaS application has active subscriptions for tenants: 50681641-b011-4073-9004-3e0267387329

    I am even not able to deploy my MTA application. It throws the following error:

    Error creating services: Error updating service “pci-registry” from offering “saas-registry” and plan “application”: Service broker operation failed: 502 Bad Gateway: Service broker error: Service broker parameters are invalid: appName can’t be changed.

    I have attached the screenshot of the same.

    Kindly help provide a solution to the same.

    Thanks and Regards


    • Hi Debojit,

      Thank you so much for your query.

      To delete a SaaS Provisioning Service the provider must ensure that there are no active subscriptions on the service.

      The flow to delete a SaaS Provisioning is as follows:

      1. Ask all tenants to un-subscribe your application.
      2. Verify that no active subscriptions are present on your service.
      3. Delete the SaaS provisioning service.

      For the other issue that you have encountered, I need more information. Can you please reach out to me internally?

      Thank you so much for your cooperation.

      I hope this response helps you.

      Warm Regards

      Sandeep T D S



    I am trying to subscribe a tenant to my multitenant application written in java. I am on canary.

    From the tenant account, when i click on subscribe, the status shows as processing for sometime and then comes back to unsubscribed.

    when trying to subscribe through the REST API, I am able to get the access token,

    but when i hit the tenant onboarding url, i am, getting access denied error.

    I think I am missing something here.

    can you please help me with this.

    Maybe we can connect internally.

    • Hi Nandan,

      Thank you so much for your query.

      From what you've described in your comment, I believe the error could be in your application - either where you are defining the callbacks or where you configure the authentication.

      Can you please refer to this sample application, written in JAVA, and try to identify if there's any deviation in your implementation?

      If you do not find any parity, I will be happy to assist you further.

      Warm Regards
      Sandeep T D S


    I'm trying to create a multi-tenant application based on HANA.

    Is it possible that we can grant some HANA db roles to tenant user when they subscribe the application?


    Thanks in advance,




    Thanks for your blog.

    I have a question about the destination on multi-tenant. We use the destination on CF to connect the S/4 HANA system.

    Now the multi-tenant application is deployed in CF canary as provider subaccount.

    How the application could get the destination in consumer subaccount during runtime?

    Then we can connect to according S/4 HANA system base on consumer destination configuration.

    Best Regards

    Clark Huang

    • Hi Clark,


      Thank you so much for your question.

      Jan Rumig would be able to help us out over here.

      Jan, can a multi-tenant application consume destinations defined in the consumer sub-account? Thank you for looking into the query.


      Sandeep T D S


          • Hi Samuele,

            this can be achieved with the getDependencies callback as mentioned here:

            I guess, you have a multitenant application? When this gets subscribed, you have to return the dependency to the destination service and thus this one gets subscribed as well. Afterwards you should be able to read the destinations from the consumer tenant.

            Some details could be found here:

            Best regards,


          • Hi Jan,

            We have a similar requirement. We have created a multi-tenant fiori application hosted by the provider subaccount and we are successfully able to subscribe to the same from the consumer subaccount. But now, we would want the consumer application to read the data from the destination in the consumer subaccount itself.

            The first thing that you mentioned to achieve this, is to include the getDependencies while registering the multi-tenant application with the Saas Provisioning service. Once this is done what would be the next steps involved? What are the changes required in the fiori application created using web ide to enable it to read the destination from the consumer account?

            Can you please point to any blog or any detailed documentation on how this can be achieved?


            Sangita Purkayastha



          • Hi Sangita,

            you also have create an instance of the destination service and bind it to your application. After doing this, you find the credentials for your application in the environment variables.

            Now, when you want to access the destination service, you have to exchange the token and then forward the new token to the destination service.

            Best regards,


          • Hi Jan,

            After having subscribed to the application successfully from my consumer subaccount, I would now want to read the destination from our consumer subaccount.

            Since my application is hosted in the provider subaccount (and we were reading the destination until now from the provider subaccount), so binding the application with the destination service instance is only possible in the provider subaccount. How can we do this for the destination in the consumer subaccount?


            Sangita Purkayastha

          • Hi Sangita,

            same as described before: you have to bind the destination service to your application within your provider account. After providing the destination service in the getDependencies() callback, the destination service is subscribed for new subscriptions. This "forwarded" subscription allows you to read the destinations for the consumer accounts.

            Technically, you have to exchange the token with XSUAA, so that the correct information is contained in it. With this new token, you then call the destination service.

            Best regards,


  • Hi Sandeep,

    My provider sub account and consumer sub account belongs to different infrastructure provider and regions in the same global account. Can consumer sub account still be able to subscribe the application deployed in provider sub account? I have tried with the sample "Hello World" application:

    But i cant see the application in consumer sub account under Subscriptions page/option.




    • Hi Ravindra,

      Thank you for your question.

      This feature was not available when we wrote the blog. I have since moved to a new project.

      Jan Rumig should be able to help us out. Jan, can you please comment? Thank You.


      • Hi Ravindra,

        have you registered your application with the SaaS Provisioning service?

        See some details in the help page, step 5:

        Best regards,


        • Hi Jan,

          Thanks for your reply.

          Yes, I have registered the application mt-hw-node-app with the SaaS Provisioning service as explained in the blog and SAP help portal. But still i cant see the SaaS application in consumer sub account under Subscriptions page/option.

          Also apart from this, I am facing below issue,

          On successful deployment of the app, when i open the app-router application which is mt-hw-ar-app in the provider sub-account i am getting error “The subdomain does not map to a valid identity zone.” instead of Hello message.

          Is this something to do with TENANT_HOST_PATTERN. I have mentioned value as “^(.*)” in mta.yaml under mt-hw-ar-app application.

          When i remove the Tenant-Host Pattern and make other required changes (change UAA service to dedicated in xs-security.json) and deploy the application, i can see the Hello message if i open the app-router application mt-hw-ar-app in the provider sub-account.



    • Hi Sindy,


      Thank you for reaching out to me. I've written an e-mail to you. Can we please discuss this over a quick call?


      Thank you
      Sandeep T D S


    Could you help me ? I am sap partner and I have plans to create an application saas multi-tenant .

    I saw that is possible using sub account in the same global account.

    But my approach will be different, I need that my customers subscribe in my application using their global account.

    Where I can find documentation about this ? e.g partner sale in SAP Store.

    • Hi Erico,

      thanks for the question.

      As documented: currently, customers of partner applications can only be subscribed from a subaccount within the same global account.

      We will update you, if there will be a change later.

      Thanks and best regards,


        • Hi Erico,

          I would recommend to you, to go ahead with the current possible setup. Provide every customer of yours, a separate subaccount and subscribe this to your application in your provider subaccount.

          There is no naming convention for applications in cloud foundry.

          Best regards,



    Thanks for the wonderful blog.

    Do you have any blog that automates the process of route mapping manually?  If so, could you please attach the link here?  Thanks in advance.


    with Regards,

    Antony Jerald.

  • Hi Sandeep,

    Thank you for the awesome blog.

    I had successfully deployed the multi tenant application  when i open the app-router application  i am getting error “The subdomain does not map to a valid identity zone.”

    Can you please provide solution for this.

    Thanks in advance




    • Hi Daraksha,

      Thank you so much for raising your issue.

      Your issue seems similar to an issue raised earlier. Does the answer mentioned here help?

      Warm Regards
      Sandeep T D S

  • Thanks a lot SANDEEP TDS for write up with simple example.

    I have few questions on the scope of SaaS subscription limited to a global account.

    1. How do a global account and sub account is provisioned to customers i.e. tenants? As a software provider, do you need to create sub accounts for all customers in the global account where provider sub account is present?
    2. Can you provide a business use case where SaaS provisioning would be useful? I mean who would be the provider and who would be the targeted consumers.
    3. How does the API Service be designed with respect to provisioning? Let say I have a API in one of the sub account and I want other application on different other global accounts to use it.
    4. How does it look if I want to develop a API service with multi tenancy? Let say a multi tenant application in SAP CP of other global account uses API Service and API service want to ensure application accesses API service on behalf of a tenant. i.e. via some auth mechanism.

    thanks for this blog, which is still very helpful.

    One question: Should we have one saas-registry service per multi-tenant application or can several multi-tenant applications in the same space share a common saas-registry service?



    • Hi Wolfgang,

      Thank you for raising your question.

      I personally recommend using one instance of saas-registry service per multi-tenant application. Doing so would help you in maintaining your application.

      Warm Regards
      Sandeep T D S

  • Hi Sandeep,


    Thanks for the blog.

    One question is, If in the new version of the application, if we change the go to application url in the subscription callback, then is there a way to refresh all the existing subscriptions to point to this new go to application URL ?





    Thanks for the blog.

    We have exposed a SaaS application in CF canary landscape.After subscribing when I launch the application , it gives "Your connection is not private"error as shown below.

    Do you know why such an error comes?



    • Hi Swetha,

      Thank you for your question.

      As far as I can tell, your application URL is not trusted.
      You need to add this URL format as a trusted URL.

      However, you will not face this issue in production systems.
      To mitigate the issue, you would have to create custom domains.

      Please see this comment for more details. 


      Warm Regards

      Sandeep T D S

  • Hi Sandeep

    Thanks for the great article.

    I'm trying to develop a shell plugin using a launchpad module, I followed all the steps in the documentation and I'm able to successfully subscribe to the subscription. Routes were also configured and I can run the app in a different subaccount using that route url. However, I need to integrate this plugin with the Portal service and I do not see the plugin listed as a content provider in the Content Explorer of Site Manager in the Portal.

    Do you have any advice on how to use the newly created subscription as a content provider in Portal? I've followed the steps described here: Expose Your App as a Content Provider



  • Hi Sandeep.

    I have a app specific (not tenant specific) url which shows the api documentation of my application. I wish to add just the basic username and password authentication on this url (so that its accessible to only internal saas owners) while all the tenant specific routes should continue to work the way as you mentioned. Do you have any suggestion on how can I add a new addition in either app router or tenant host pattern to include a app specific route with just simple username and password authentication as this url is just for internal saas app owners and I dont wish to expose it to the public on internet?

    FYI, I tried mapping this app-specific route (say, SaaSAppName.Domain/v1/docs) to my app router and then, accessing the url redirected me to my app router for login. But my login fails with error: Unable to verify username or password. Please try again. 

    I have already configured the spring security for this route as well in my Security class (I am not checking scopes for this url): .mvcMatchers(GET, "/v1/docs").authenticated();



    Kush Sharma

  • Hi Sandeep,

    I have built  a search engine which is an entity agnostic, rest api exposed and built using opensource apache Lucene. Wanted to make it as a SaaS service, so that other product/s can use/bind it   easily.

    I just need to push as a SaaS service, is there quick way to do that.


    Mohan Ramu