Showing results for 
Search instead for 
Did you mean: 

Handle JWT token in CAP and forward it


I am having a running a pure API service (developed with CAP) with no UI that currently authenticates with grant type "client_credentials" to a BTP destination with basic authentication (fixed technical user). The service calls some OData services on a S/4 on-prem system.

Now I have the requirement to change the grant type to "password" in order to know what user did what and when especially when data have been created or modified. I am now using a destination with principal propagation for authorization.

The CAP service receives the JWT token grant type "password" within the header information of the request. But somehow the actual call of the destination is made with a token grant type "client_credentials" which of course causes a 401 error.

I did these steps which I've found on the internet:

- add "forwardAuthToken": true to credentials of CDS definition in package.json

- added approuter with "cds add approuter" and added "forwardAuthToken": true in properties

In server.js I had this coding before

const uaaServices = xsenv.getServices({ uaa: { tag: 'xsuaa' } })

const passport = require('passport')

const JWTStrategy = require('@sap/xssec').JWTStrategy

passport.use(new JWTStrategy(uaaServices.xsuaa))


app.use( ['/endpoint*', '/other/endpoint*'], 


passport.authenticate('JWT', { session: false }), 

(req, res, next) => { 

if (!req.authInfo) { 

return res.status(401).end() 

} else { 

return res.status(403).end() next() 

} } 


Does this somehow interfere with the token coming in as request header?

Active Contributor
0 Kudos

Can you please answer the following questions for clarification:

  1. Why do you need the server.js?
  2. You say that you're providing a pure "API service". So why to you have an approuter? Your clients could authenticate to the XSUAA using grant_type=password and use the returned JWT directly against the CAP Service.
  3. Do you see the request in the Cloud Connector logs? What user is shown in the Cloud Connector?
0 Kudos

Hi Gregor and thanks for reaching out.

A bit of a background: the CAP service offers an abstract and simplified API layer to handle requests towards an S/4 on-prem system for functional locations and equipments. The service itself (unfortunately) also contains a lot of business logic to modify and transform incoming requests to match the SAP Odata structure and vice versa.

Why server.js? It was my first major CAP project and I basically followed the "Getting Started" and "Cookbook" chapters of And during development the idea shifted from a fullstack app with UI and service to a "API only" service.

The user authorization works as you said: a token with grand_type=password is created (with the service's oauth/token URL) and is sent towards the service with every request. When I debug the service, I see in req.headers.authorization the token and with req.authInfo.getGrantType() that the grant_type is "password". The approuter was one approach I read about it within the last of days. I doubt it that this would be helpful but you never know. I've already removed it.

But as soon as the actual call of the Odata Service is made with for e.g. a simple GET request in the service implementation during this.on('READ', 'FunctionalLocation', async (req) => {}) event the req.header is empty. So I assume that CAP automatically generates a new token but only grant_type=client_credentials. This is also the token I see when I run the logs with "cf logs serive-name" including the error "Failed to load destination. Caused by: No user token (JWT) has been provided. This is strictly necessary for 'PrincipalPropagation'." Unfortunately I don't have access to the cloud connector and its logs but I assume that the logs basically show the same error messages and tokens with command "cf logs".

Accepted Solutions (0)

Answers (0)