Technology Blogs by SAP
Learn how to extend and personalize SAP applications. Follow the SAP technology blog for insights into SAP BTP, ABAP, SAP Analytics Cloud, SAP HANA, and more.
cancel
Showing results for 
Search instead for 
Did you mean: 
CarlosRoggan
Product and Topic Expert
Product and Topic Expert

or:


Calling
oauth & scope protected app
from other app
using client credentials
and as external user


or:


How to assign scope
to foreign app
and external user


The problem I’d like to address with this tutorial is the following:
Scenario: In SAP Cloud Platform, we have app 1 and app 2:








App1:
Provides API
protected with OAuth2
requires scope
< - - - - > App 2:
The client app
that calls app 1

The problem:
To call the API, the cliet has to do the OAuth flow programmatically, that's no issue.
BUT:
The JWT token doesn’t contain the scope which is required by app 1
How to assign a role to an app???

Quicklinks:
Quick Guide
Sample Code



Prerequisites



  • We choose Node.js to write the little apps
    So you need to have Node.js installed on your machine
    See here for little help, no need to be very familiar with node.js development

  • Access to SAP Cloud Platform, Trial account (see here)

  • Some experience with app development, app deployment

  • Command Line Client for Cloud Foundry (see here) is not a must, but useful


Overview


1 Create API Provider App
2 Call API with human user
3 Create Client App and call API

Appendix: All Sample Project Files

Preparation: Create Project Structure


Create base project folder for our 2 apps:
C:\tmp_app2app
Inside, we create 2 root folders for our apps, and in addition, a third folder for our optional human test:
apiproviderapp
clientapp
humanuser

See screenshot:




Step 1: Create API Provider App


First we create our app 1,  the app which provides protected API, we call it providerapp
To protect our app, we use the XSUAA (Extended User Authentication and Authorization) service in SAP Cloud Platform

1.1. Create XSUAA instance


To create an instance of xsuaa, we define first the configuration parameters, which are required during instance creation.
The parameters can be copy&pasted directly in the cloud cockpit, but it is better to store it in a descriptor file

Jump into C:\tmp_app2app\apiproviderapp
Create a file called xs-security.json

Note:
The name is not relevant, you can use any name of your choice
But xs-security.json is the usual name

Copy the following content:
{
"xsappname" : "xsappforproviderapp",
"tenant-mode" : "dedicated",
"scopes": [{
"name": "$XSAPPNAME.scopeforproviderapp",
"granted-apps" : [ "$XSAPPNAME(application,xsappforhumanuser)"],
"grant-as-authority-to-apps" : [ "$XSAPPNAME(application, xsappforclientapp)"]
}],
"role-templates": [ {
"name" : "TheProviderRoleTemplate",
"default-role-name" : "TheRoleForProviderApp",
"scope-references" : ["$XSAPPNAME.scopeforproviderapp"]
}]
}

With this configuration, we define a scope and new role in SAP Cloud Platform
That role can be assigned to users
Later, we will bind our app to this instance of xsuaa, and with the help of xsuaa, we'll ensure that the API can only be invoked if the caller has that scope

Note:
The role-templates section is only required for human users.
If you’re planning to skip the optional chapter 2, you can remove that part from the json

Note:
The value of xsappname property must be unique in the identityzone

Note:
Prefixing the scope name with the variable $XSAPPNAME makes the scope name unique and accessible
The variable will be resolved by the platform, we will see it below

Let’s continue
Based on the xs-security.json file, we can create the instance of xsuaa service, with name xsuaaforprovider

In command prompt, folder apiproviderapp, run the following command

cf cs xsuaa application xsuaaforprovider -c xs-security.json

The syntax:
create service instance of service <xsuaa> and service plan <application>. Then the desired <name> of the instance and the <configuration> params as file

You can also use the cloud cockpit and use the xs-security.json file in the creation wizard

After the service instance is created, we can use it in our app.

1.2. Create app


Our app is a silly little app which exposes a silly REST endpoint
Nevertheless, the app absolutely wants to protect the endpoint with OAuth2
That's tedious enough....but:
Furthermore, the app wants that whoever is silly enough to call the endpoint, he must have a role (scope) assigned

Installation

In folder C:\tmp_app2app\apiproviderapp create a file called package.json

With following content:
{
"main": "server.js",
"dependencies": {
"@sap/xsenv": "latest",
"@sap/xssec": "latest",
"express": "^4.16.3",
"passport": "^0.4.1"
}
}

The dependencies are required to start a server and to add security
To install the dependencies, open command prompt, jump into folder apiproviderapp and execute the command npm install
See here:


Implementation

In the folder C:\tmp_app2app\apiproviderapp create a file called server.js
Copy the full content which can be found in the appendix section

Explanation:
Our little app exposes a REST endpoint which just returns a message.
app.get('/getData', function(req, res){   

The authorization header, which contains a JWT token, is analyzed to view if the required scope is present.
const MY_SCOPE = xsuaaCredentials.xsappname + '.scopeforproviderapp'// scope name copied from xs-security.json
if(req.authInfo.checkScope(MY_SCOPE)){
res.send('The endpoint was properly ca

The check for valid JWT token is done by passport module
app.use(passport.initialize());
app.use(passport.authenticate('JWT', { session: false }));

In addition, just for our convenience, we add a middleware which is invoked prior to all other code.
app.use(jwtLogger)

This middleware just decodes and prints the relevant content of the JWT token
function jwtLogger(req, res, next) {
const jwtToken = readJwt(req)
console.log('===> JWT: scopes: ' + jwtToken.scope);

1.3. Deploy


In our app folder C:\tmp_app2app\apiproviderapp we create a file with name manifest.yml
The content:
---
applications:
- name: providerapp
memory: 128M
buildpacks:
- nodejs_buildpack
services:
- xsuaaforprovider

Explanation:
We define a name for our app in the cloud
We declare a dependency to the instance of xsuaa service which we created earlier

To deploy, we run the following command in the same folder apiproviderapp
cf push
(requires the Command Line Client, see prerequisites)

Step: 2 Call API with human user


After deployment, we can invoke the endpoint of our app in the browser.
https://providerapp.cfapps.eu10.hana.ondemand.com/getData
Result: 401 Unauthorized
We check the logs with cf logs providerapp –recent
Result: No relevant info in the log
Our endpoint implementation is not even reached.
Reason: we haven’t sent a JWT token
Consequence: We need to do the OAuth flow

How to call an OAuth protected service that requires OAuth flow?
I’ve described it in detail in this blog
So here I’m only giving short description

How do we get a JWT token?
We have to use xsuaa

2.1. Create xsuaa


So we create a new instance of xsuaa, with name xsuaaforhuman
Why create a new instance of xsuaa, why not use the one we created above?
That would be possible, but we’re assuming a scenario where the user is not the same person who created the API provider app

In folder C:\tmp_app2app\humanuser we create a file xs-security.json with following content
{
"xsappname" : "xsappforhumanuser",
"tenant-mode" : "dedicated",
"foreign-scope-references": [
"$XSAPPNAME(application,xsappforproviderapp).scopeforproviderapp"
]
}

Explanation:
The syntax is:
<service plan>, <xsappnameofprovidingxssecurityfile>.<scopename>

Note:
Make sure not to use e.g. the instancename, or applicationname, or the rolename

Note:
Alternatively, the following statements are valid as well:
"$XSAPPNAME(application,b2d58db5-635f-44a2-97d6-8b23be70fd5c,xsappforproviderapp).scopeforproviderapp"

Above one contains the subaccount id
Below one is using the resolved xsappname instead of the variable
"xsappforproviderapp!t45671.scopeforproviderapp"

Now, to create the instance of XSUAA, open command prompt, step into folder
C:\tmp_app2app\humanuser and run

cf cs xsuaa application xsuaaforhuman -c xs-security.json

Or use the cockpit to create an instance with name xsuaaforhuman

Since we’re a human, we cannot bind ourself to the service.
As such, we need to create a service key.
That can be done in the cockpit, in the details screen of the service instance
Or on command line:
cf csk xsuaaforhuman serviceKeyForHuman
Syntax:
Create service key for instance and give the desired name

Then we have to view the content of the service key.
In the cockpit it is visible, on command line run:

cf service-key xsuaaforhuman serviceKeyForHuman

Now, from the service key, take a note of the following properties:

"clientid": "sb-xsappforhumanuser!t12345",
"clientsecret": "CLLaQTTjfG1i9PGrBrRLaIigpjo=",
"url": "https://123abc456trial.authentication.eu10.hana.ondemand.com",

2.2. Call API with REST client


Now use a REST client tool which supports OAuth to fetch a JWT token and call our REST endpoint
Support for OAuth means that the tool does an additional request (to fetch the token) before it executes the actual desired request to the endpoint
In the details dialog for OAuth2, enter the following details:























Authorization OAuth2
Grant Type Password
URL append oauth/token to the url property
e.g.
...authentication...ondemand.com/oauth/token
User / Password your own Cloud Platform user/password
ClientID / secret values from properties from service key

The screenshot shows the configuration in postman:


Press "request", then "use token", then "send"

Result: 403 Forbidden
AGAIN!
But this time, in the logs, we can see that the JWT has been sent, but it doesn’t contain the required scope
Reason:
As a foreign user we want access to foreign scope, as declared in our xsuaa descriptor
But wanting it is not enough.
The providing app has to allow it
That's fair enough...

2.3. Grant the scope


As a provider app, I can allow a foreign user to use my scope
What is a "foreign user"?
That's somebody who uses a different instance of XSUAA
To allow, I have to GRANT my scope to the foreign user
The foreign user is represented by the instance of xsuaa which he is using
And the instance of xsuaa is represented by the property xsappname
As such, the provider app grants the scope to the foreign xsappname
xsappname is called "app", see below.

As such, the statement is:
"granted-apps" : [ "$XSAPPNAME(application,xsappforhumanuser)"]

Syntax:
<service-plan>,<xs-app-name>

As a provider app, I have to add this statement to my xsuaa descriptor when creating the instance of xsuaa

The excerpt of xs-security.json
"xsappname" : "xsappforproviderapp",
"scopes": [{
"name": "$XSAPPNAME.scopeforproviderapp",
"granted-apps" : [ "$XSAPPNAME(application,xsappforhumanuser)"]
}],
...

See appendix for full file content

In our tutorial, we’ve already created the xsuaa instance (providerapp), so now, we have to “update” the instance, to make the changed parameters effective
Updating a service instance can be done in the cockpit - or in command prompt:

cf update-service xsuaaforprovider -c xs-security.json

If you don’t use the command line, you have to delete the xsuaa instance in the cockpit, then re-create it with new parameters

After updating the xsuaa of the provider app, we have a nice relation between the 2 xsuaas:
The provider does “grant”, the humanuser does “reference” it


We can try the request with postman again:
fetch new token, use it, then send the request
But we still get forbidden and in the log we still don’t see the scope in our JWT token

One more step is required:
The human user needs to have the corresponding role assigned
Remember: the api provider app not only defined a scope (with grant), but also defined a role-template, based on the scope.
Like that, the role can be assigned to human users

2.4. Assign Role to user


In Cloud Cockpit, go to subaccount
On the left menu: Security->Role Collections
Create a Role Collection with a name of your choice
Click the new Role Collection, then “Add”
In the dialog, choose the application identifier, e.g.
xsappforproviderapp!t12345

Note:
Remember?
This is the value we gave for property xsappname in the xs-security.json file
The platform has generated the full name.
That’s why we couldn’t hardcode it in the application code of our provider app

After adding the role to the role collection, we have to assign the role collection to our user
In subaccount, Security->Trust Configuration click on the active entry ("sap.default")
Enter the e-mail address then click Show Assignments, then Assign Role Collection
Choose your new Role Collection, close the dialog
Now your user owns that role (the scope defined by the xsuaa bound to providerapp)

Call endpoint

In postman, request new token, use it, send the request to the endpoint of providerapp
Finally, the request is successful
We see in the log that the scope was contained in the JWT token


Recap

Scenario:
There’s a provider app which requires a scope
And there’s a human foreigner which wants to call that app
The human user is a foreigner because he has his own xsuaa
To enable this scenario:
1. the provider app has to grant the scope explicitly to the foreign xsuaa
2. the foreign xsuaa has to explicitly reference the granted scope
3. the foreign human user needs the (greanted) role assigned to him

Note:
Instead of postman, we could have used an app router. See here

Diagram



Step 3: Create Client App and call API


Now we're coming to the actual purpose of this tutorial:
we want to call the endpoint of the provider app programmatically, from a second app
This app as well needs its own instance of xsuaa
In the previous, optional chapter, we’ve learned that the 2 involved xsuaa instances have to reference each other
However, the mechanism is different for client apps than for human users.

Let’s see

3.1. Create xsuaa for client app


In foder C:\tmp_app2app\clientapp we create a new xs-security.json file with content:
{
"xsappname" : "xsappforclientapp",
"tenant-mode" : "dedicated",
"authorities":["$ACCEPT_GRANTED_AUTHORITIES"]
}

The relevant line here is the “authorities” property.
This means, with other words, that the client app wants to use the authorities which are granted by providing app

Note:
This statement can be refined to accept only certain scope:
"authorities":["$XSAPPNAME(application,xsappforproviderapp).scopeforproviderapp"]

Or this variant works as well, easier to read, with resolved variable (but don’t use it)
"authorities":["xsappforproviderapp!t45671.scopeforproviderapp"]

Note:
Foreign-scope-reference doesn’t work
That’s only used in user-centric scenarios

To create this service instance, open command prompt and make sure to step into in the clientapp folder
Then execute the following command
cf cs xsuaa application xsuaaforclient -c xs-security.json

Note:
We don’t need to create service key, because we’re going to bind the client app to this xsuaa instance

3.2. Update the providing xsuaa


Now we need to change the xsuaa descriptor of the providing app.
In order to allow a scope to a foreign app (not user), the following statement is used:
"grant-as-authority-to-apps" : [ "$XSAPPNAME(application, xsappforclientapp)"]

As we can see, here the scope is granted as “authority”

Syntax:
<service plan>, <xsappnameofusingapp>

Note:
Make sure to enter the correct xsappname of the xsuaa created above for the client

The relevant excerpt of file C:\tmp_app2app\apiproviderapp\xs-security.json:
"xsappname" : "xsappforproviderapp",
"scopes": [{
"name": "$XSAPPNAME.scopeforproviderapp",
"grant-as-authority-to-apps" : [
"$XSAPPNAME(application, xsappforclientapp)"
...

See appendix for full file content

After changing the xs-security.json file, don’t forget to call the "update-service" command
Open command prompt in folder C:\tmp_app2app\apiproviderapp and run
cf update-service xsuaaforprovider -c xs-security.json

After updating the xsuaa of the provider app, we have a nice relation between the 2 xsuaas:
The provider does “grant”, the client does “accept” it:



3.3. Create the client app


package.json

In folder C:\tmp_app2app\clientapp create a package.json file and copy the content from the appendix section

server.js

In folder C:\tmp_app2app\clientapp create a server.js file and copy the content from the appendix section

In the implementation, we do the following:

- access the OAuth credentials from the environmentThis is possible because the app is bound to the xsuaa service instance
It is required because we need the client id and secret and token-url
(what we used in postman request)
We need it in order to fetch the JWT token from xsuaa server
const VCAP_SERVICES = JSON.parse(process.env.VCAP_SERVICES)
const CREDENTIALS = VCAP_SERVICES.xsuaa[0].credentials
const OA_CLIENTID = CREDENTIALS.clientid;

- execute an https call to fetch the token
const fetchJwtToken = function() {
...
const options = {
Authorization: "Basic " + Buffer.from(OA_CLIENTID + ':' + OA_SECRET).toString("base64")
...
https.get(options, res => {
...

- use the token to call the endpoint of the provider app
const doCallEndpoint = function(){
...
const options = {
host: 'providerapp.cfapps.eu10.hana.ondemand.com',
path: '/getData',
...
Authorization: 'Bearer ' + jwtToken
...
const req = https.request(options, (res) => {

- to make this procedure accessible in the cloud, we start a server and offer an endpoint
app.get('/trigger', function(req, res){  
...
app.listen(process.env.PORT, ()=>{})

See appendix for full file content

3.4. Deploy the client app


In folder C:\tmp_app2app\clientapp create a manifest.yml file and copy the content from the appendix section
...
- name: clientapp
services:
- xsuaaforclient

In the manifest we declare a dependency to the xsuaa instance created above

Call provider app from client app

After deployment, we can invoke the endpoint of our client app in a browser
...fortunately, this endpoint is not protected at all...;-)

https://clientapp.cfapps.eu10.hana.ondemand.com/trigger

As a result, we get a success message

Recap

To enable communication between 2 apps, using different xsuaa, but in same subaccount:
1. in protected app (provider), the scope must be „granted“ to the client-xsuaa
2. in using app (client), the “authorities” property is required in xs-security.json

Note:
If you need a scenario where the apps are located in different subaccounts, refer next tutorial

Diagram



Summary


Thanks for reading this blog.
I hope it has helped to solve these tedious authorization-problems

We have covered 2 scenarios:

A) Protected app is called by external user:
The app is protected with OAuth and defines a scope and a role
The external user creates his own xsuaa instance to call that API
B) Protected app is called by client app
The app is protected with OAuth and defines a scope
The client app wants to call the API and somehow needs to have that scope

Note:
More information about JWT tokens can be found in this blog post

Troublemaking



  • If the forbidden-error persists, then probably there is any typo in one of the xs-security.json files

  • As mentioned above: make sure that you enter the value of the property xsappname (copy it from xs-security file), not instance name nor app name

  • When executing the update-service command, make sure to step into the correct folder, such that you don’t e.g. update the provider-xsuaa with the content of the other client-xs-security

  • To avoid such a copy&paste error, or error with history of cmd, you can choose different names for each xs-security.json file (e.g. xs-sec-provider.json, etc)

  • Make sure that you’re running the scenario in the same subaccount
    If you need 2 subaccounts, see the next tutorial

  • When using REST client, make sure to select the appropriate grant type. User credentials do work only if user has roles

  • In case of user: didn't forget to add role collection to IDP?

  • If the problem persists: if you're using old client lib, it might be necessary to add the trust variable to the env of your app
    This is done by adding the following snippet to your manifest.yml
    (Alternatively, it can be added in the cockpit or with set-env command. In these cases, make sure to restart or restage your app)
    See this blog postfor detailed info.
    his variable tells the xssec validator to accept foreign clientids and identitiyzones
    manifest.yml:
    env:
    SAP_JWT_TRUST_ACL: >
    [
    {"clientid":"*", "identityzone":"*"}
    ]​



Quick Guide


App requires OAuth and scope

A) Protected app is called by external user:
We need:
1. "granted-apps" (in provider-app-xs-security.json)
2. "foreign-scope-references" (in human-user-xs-security.json)
3. Assign role to user

B) Protected app is called by client app
We need:
1. "grant-as-authority-to-apps" (in provider-app-xs-security.json)
2. "authorities" (in client-app-xs-security.json)

Links


Next Tutorial: same scenario, but with different subaccounts

Docu: SAP Help Portal

Useful info about security in this series: Blog series
OAuth 2.0
Understanding of OAuth for dummies like me.

JWT tokens info in this blog post
How to add custom property to JWT token
Little app router series
OAuth flow with REST client: here

Security Glossary.

Appendix: All Sample Project Files


For your convenience, see screenshot for overview about project structure



App 1: API Provider App


xs-security.json
{
"xsappname" : "xsappforproviderapp",
"tenant-mode" : "dedicated",
"scopes": [{
"name": "$XSAPPNAME.scopeforproviderapp",
"granted-apps" : [ "$XSAPPNAME(application,xsappforhumanuser)"],
"grant-as-authority-to-apps" : [ "$XSAPPNAME(application, xsappforclientapp)"]
}],
"role-templates": [ {
"name" : "TheProviderRoleTemplate",
"default-role-name" : "TheRoleForProviderApp",
"scope-references" : ["$XSAPPNAME.scopeforproviderapp"]
}]
}

package.json
{
"main": "server.js",
"dependencies": {
"@sap/xsenv": "latest",
"@sap/xssec": "latest",
"express": "^4.16.3",
"passport": "^0.4.1"
}
}

server.js
const express = require('express');
const passport = require('passport');
const xsenv = require('@sap/xsenv');
const JWTStrategy = require('@sap/xssec').JWTStrategy;

//configure passport
const xsuaaService = xsenv.getServices({ myXsuaa: { tag: 'xsuaa' }});
const xsuaaCredentials = xsuaaService.myXsuaa;
const jwtStrategy = new JWTStrategy(xsuaaCredentials)

// configure express server with authentication middleware
passport.use(jwtStrategy);
const app = express();

// Middleware to read JWT sent by client
function jwtLogger(req, res, next) {
console.log('===> Decoding auth header' )
const jwtToken = readJwt(req)
if(jwtToken){
console.log('===> JWT: audiences: ' + jwtToken.aud);
console.log('===> JWT: scopes: ' + jwtToken.scope);
console.log('===> JWT: client_id: ' + jwtToken.client_id);
}

next()
}

app.use(jwtLogger)
app.use(passport.initialize());
app.use(passport.authenticate('JWT', { session: false }));

// app endpoint with authorization check
app.get('/getData', function(req, res){
console.log('===> Endpoint has been reached. Now checking authorization')
const MY_SCOPE = xsuaaCredentials.xsappname + '.scopeforproviderapp'// scope name copied from xs-security.json
if(req.authInfo.checkScope(MY_SCOPE)){
res.send('The endpoint was properly called, role available, delivering data');
}else{
const jwtToken = readJwt(req)
const availableScopes = jwtToken ? jwtToken.scope : {}

return res.status(403).json({
error: 'Unauthorized',
message: `Missing required role: <scopeforproviderapp>. Available scopes: ${availableScopes}`
});
}
});

const readJwt = function(req){
const authHeader = req.headers.authorization;
if (authHeader){
const theJwtToken = authHeader.substring(7);
if(theJwtToken){
const jwtBase64Encoded = theJwtToken.split('.')[1];
if(jwtBase64Encoded){
const jwtDecoded = Buffer.from(jwtBase64Encoded, 'base64').toString('ascii');
return JSON.parse(jwtDecoded);
}
}
}
}

// start server
app.listen(process.env.PORT || 8080, () => {
console.log('Server running...')
})

manifest.yml
---
applications:
- name: providerapp
memory: 128M
buildpacks:
- nodejs_buildpack
services:
- xsuaaforprovider
env:
DEBUG: xssec:*

App 2: Client App


xs-security.json
{
"xsappname" : "xsappforclientapp",
"tenant-mode" : "dedicated",
"authorities":["$XSAPPNAME(application,xsappforproviderapp).scopeforproviderapp"]
}

package.json
{
"dependencies": {
"express": "^4.16.3"
}
}

server.js
const express = require('express')
const app = express()
const https = require('https');

// access credentials from environment variable (alternatively use xsenv)
const VCAP_SERVICES = JSON.parse(process.env.VCAP_SERVICES)
const CREDENTIALS = VCAP_SERVICES.xsuaa[0].credentials
//oauth
const OA_CLIENTID = CREDENTIALS.clientid;
const OA_SECRET = CREDENTIALS.clientsecret;
const OA_ENDPOINT = CREDENTIALS.url;

// endpoint of our client app
app.get('/trigger', function(req, res){
doCallEndpoint()
.then(()=>{
res.status(202).send('Successfully called remote endpoint.');
}).catch((error)=>{
console.log('Error occurred while calling REST endpoint ' + error)
res.status(500).send('Error while calling remote endpoint.');
})
});

// helper method to call the endpoint
const doCallEndpoint = function(){
return new Promise((resolve, reject) => {
return fetchJwtToken()
.then((jwtToken) => {

const options = {
host: 'providerapp.cfapps.eu10.hana.ondemand.com',
path: '/getData',
method: 'GET',
headers: {
Authorization: 'Bearer ' + jwtToken
}
}

const req = https.request(options, (res) => {
res.setEncoding('utf8')
const status = res.statusCode
if (status !== 200 && status !== 201) {
return reject(new Error(`Failed to call endpoint. Error: ${status} - ${res.statusMessage}`))
}

res.on('data', () => {
resolve()
})
});

req.on('error', (error) => {
return reject({error: error})
});

req.write('done')
req.end()
})
.catch((error) => {
reject(error)
})
})
}

// jwt token required for calling REST api
const fetchJwtToken = function() {
return new Promise ((resolve, reject) => {
const options = {
host: OA_ENDPOINT.replace('https://', ''),
path: '/oauth/token?grant_type=client_credentials&response_type=token',
headers: {
Authorization: "Basic " + Buffer.from(OA_CLIENTID + ':' + OA_SECRET).toString("base64")
}
}

https.get(options, res => {
res.setEncoding('utf8')
let response = ''
res.on('data', chunk => {
response += chunk
})

res.on('end', () => {
try {
const jwtToken = JSON.parse(response).access_token
resolve(jwtToken)
} catch (error) {
return reject(new Error('Error while fetching JWT token'))
}
})
})
.on("error", (error) => {
return reject({error: error})
});
})
}

// Start server
app.listen(process.env.PORT || 8080, ()=>{})


manifest.yml
---
applications:
- name: clientapp
memory: 128M
buildpacks:
- nodejs_buildpack
services:
- xsuaaforclient

Optional: Human User


xs-security.json
{
"xsappname" : "xsappforhumanuser",
"tenant-mode" : "dedicated",
"foreign-scope-references": ["$XSAPPNAME(application,xsappforproviderapp).scopeforproviderapp"]
}
42 Comments