Connecting to a Public Cloud API (from Business Accelerator Hub) via Node.js CAP application can be challenging. I hope this blog helps others attempting the same task.
• SAP BTP subaccount (Cloud Foundry)
• Service key for the target Public Cloud API
• XSUAA instance bound to your CAP app
• SAP BTP Destination service instance
• Bruno installed for manual testing
First, check which authentication methods are available for the API you plan to consume.
In my example I connect to the Specification Management API, but the steps apply to any Public Cloud API.
If the OAuth 2.0 Access Code Flow is listed under “Authentication Methods”, the API supports the authorization-code flow. That flow confirms a user context and usually grants wider authorisations, such as update and POST requests.
(OAuth 2.0 Application Flow corresponds to the client-credentials flow.)
Because our API supports the auth-code flow, we first prove we can log in by calling it via Bruno.
Create a new collection and paste the base URI of your Public Cloud API instance (you’ll find it in the service key in your service instance of the saas application your connecting to).
When you send a test GET request you will probably receive an authorisation error. Configure OAuth 2.0 on the Auth tab
Select Grant type Authorisation Code
Then fill in the below fields using your service key from your service instance
Request the token, pick your identity provider, and Bruno will return an access token. Inspect the scopes there to see what you can do.
After the manual check we can now automate the flow in a Node.js service.
Create a destination that points to the same API endpoint and bind it to your app.
The required scopes and the audience (aud) value are visible inside the Bruno access token.
the Audience should start with the client id of your CAP application on BTP
Once the destination is saved, ensure your application is bound to the Destination service.
Add every scope your service needs so the approuter, it will forward it in the user’s JWT: in my example i needed this scope.
{
"name": "$XSAPPNAME.Spc_Write",
"description": "Allow modification of specifications."
}Also reference the scope in authorities (and role templates, if used) and assign the resulting role collection to your user.
Now time to connect to the API in the code itself.
First, obtain the user’s JWT. This helper below tries every possible source and falls back to LOCAL_USER_JWT in local development:
/** Try every source for a JWT and fall back to LOCAL_USER_JWT. */
function getJwt(capReq) {
// CAP ≥ 7.3 keeps the raw token here
if (capReq.user?.jwt) return capReq.user.jwt;
// Plain HTTP / WebSocket headers
const hdrs = capReq.http?.req?.headers || {};
const token =
hdrs['x-approuter-authorization'] || // CF WebSocket
hdrs.authorization; // CF HTTP
if (token) return token.replace(/^Bearer\s+/, '');
// Last resort for local dev
return process.env.LOCAL_USER_JWT;
}When testing locally we don't have access to the user JWT so we can add it manually to the environment file so we can still test locally, below is the process to get the JWT for user testing (each token lasts about 7 to 8 hours)
https://<instance>.eu10.authentication.eu10.hana.ondemand.com/oauth/authorize
?response_type=code
&client_id=<XSUAA client id of your deployed app>
&redirect_uri=http://localhost
&state=xyzPaste your version into your browsers address bar, after login you will land on http://localhost/?code=<AUTH_CODE>&state=xyz. Copy the value of AUTH_CODE.
I made the Curl Request inside BAS itself. it will return a number of tokens, we only need the first and biggest one.
curl -v -X POST \
-u '<same client id>' \
--data-urlencode grant_type=authorization_code \
--data-urlencode code=<AUTH_CODE> \
--data-urlencode redirect_uri=http://localhost \
https://<instance>.eu10.authentication.eu10.hana.ondemand.com/oauth/tokenSave the token from the response into .env:
LOCAL_USER_JWT=<paste JWT here>const jwt = getJwt(req);
if (!jwt) req.reject(401, 'No user token found.');
const dest = await getDestination({
destinationName: '<DestinationName>',
jwt
});await executeHttpRequest(dest, {
method: 'POST',
url: `/odata/v4/api/specification/v1/${EntityName}`,
data: v
});If you reach the destination but receive 401 Unauthorized, your JWT is missing the correct scope—ask the product team which one you need.
Other common pitfall is using the different XSUAA instances to get your JWT for the local run. use your applications XSUAA client since this is the same one your application will check the token against
And that’s it! You should now be able to read from and write to the Public Cloud API. For read-only workloads the client-credentials flow is usually simpler.
If I missed anything or you’d like more details, please comment below—happy to help.
## Frequently Asked Questions
### What’s the difference between authorization-code and client-credentials flows?
The authorization-code flow runs in a user context, so it can carry user-level scopes (read, write, update). The client-credentials flow operates with a technical user—perfect for background jobs or read-only integrations.
### Why do I get “401 Unauthorized” after deployment?
Your user’s JWT is probably missing the required scope (e.g., `Spc_Write`). Make sure the scope is listed in xs-security.json, mapped to a role template, and assigned via a role collection in the BTP cockpit.
### Which audience value belongs in my destination?
Use the client ID of your CAP application’s XSUAA instance; it usually starts with `sb-<appName>!t<number>`.
Node.jsSAP Cloud Identity ServicesAPISAP AuthenticatorSAP Fiori CloudSAP Cloud Application Programming ModelSAP Business Application StudioSAP Business Technology PlatformSAP S/4HANA Cloud Public Edition ExtensibilitySAP Business Accelerator HubJavaScriptAPI Management
You must be a registered user to add a comment. If you've already registered, sign in. Otherwise, register and sign in.
| User | Count |
|---|---|
| 100 | |
| 49 | |
| 36 | |
| 26 | |
| 25 | |
| 23 | |
| 23 | |
| 22 | |
| 22 | |
| 22 |