Technical Articles
How to get authenticated user information with CAP in three different ways – Using the XSUAA API
Prerequisite
To follow-up with this blog post you must have read and completed the post: Setup project for development.
Reference the XSUAA Service
The third approach to get the authenticated user information is the most enhanced and complete one as it gets many available user data, such as ID in the source IdP, internal BTP ID and previous logon time.
It relies on the features of the Authentication and Trust Management service (namely XSUAA) accessible via REST API (/userinfo endpoint).
The good news is that the XSUAA service instance is already bound to the CAP servie, so we just need to reference it in the CAP service as the credentials of an external service. We do it by adding a “cds.requires” section to the package.json file of the CAP service.
Open-up the package.json of the CAP service (the one in the root folder of your project) and copy and paste the following code snippet right before the last curly bracket of the file:
,
"cds": {
"requires": {
"xsuaa_api": {
"kind": "rest",
"credentials": {
"url": "<from XSUAA service binding>",
"forwardAuthToken" : true
}
}
}
}
After the modification your package.json file should look like this:
Figure 8 – cds.requires added to package.json
Notice that the URL to the service host will be fetched on the fly from the XSUAA service binding, so we just leave it there as a placeholder.
Modify the “userInfoUAA” Function Handler
Now it’s time to update the code of the function handler (userInfoUAA) which will call the XSUAA API to get the authenticated user information.
As we have previously prepared a “skeleton” to implement the code for this approach (via the userInfoUAA function), now we just need to connect to the external service and replace the ‘return “”;‘ with the appropriate code to call it.
In this approach we will just return the information fetched by the “/userinfo” endpoint of the XSUAA service host.
Now, open-up the user-info-service.js file, and modify the code like demonstrated below:
NOTE: we also modified the userInfo function to preserve the code in case you’ve already completed the second approach (using the CAP request object).
module.exports = cds.service.impl(async function () {
// API reference
const api = 'xsuaa_api';
// Get the XSUAA host URL from service binding
const xsuaa_bind = JSON.parse(process.env.VCAP_SERVICES).xsuaa[0];
const api_def = cds.env.requires[api];
api_def.credentials.url = xsuaa_bind.credentials.url;
// connect to the XSUAA host
const xsuaa = await cds.connect.to(api_def);
// using req.user approach (user attribute - of class cds.User - from the request object)
this.on('userInfo', req => {
const user = {
id : req.user.id,
tenant : req.user.tenant,
_roles: req.user._roles,
attr : req.user.attr
}
return user;
});
// using the XSUAA API
this.on('userInfoUAA', async () => {
return await xsuaa.get("/userinfo");
});
});
Adjust the Index Page
The code is executed by accessing the “/user-info/userInfoUAA()” endpoint. So, let’s just set it as a link in the index.html page by modifying this line:
<li><a href="/user-info/userInfoUAA()">3. Using the XSUAA API</a></li>
By doing so, your index.html file should now look like this:
Figure 1 – New link in index.html
NOTE: if you haven’t completed the post for the first and/or second approaches (directly from the HTML5 app and/or using the CAP request object) your index.html file might look slightly different (no links for the first and/or second approaches).
Test the Approach
As previously mentioned this approach relies on the backend service. Therefore, the service must be running for it to work properly.
NOTE: you might have already executed the steps to split the Terminal if you completed the post for the second approach (using the CAP request object), so you may skip them.
In the Terminal, let’s make sure to be positioned in the project root folder (“user-info“) – if not already there. If you where running the first approach you might have ended up in the “app” folder after pressing CTRL-C, so just go back with: cd ..
Click on the prompt in the current opened Terminal, then in the top menu of Business Application Studio click on Terminal and select Split Terminal:
Figure 2 – Terminal menu
Now, your Terminal window, should have been split into two like demonstrated below:
Figure 3 – Split Terminal
Let’s first start the backend service. In the first Terminal run the command:
cds watch --profile hybrid
This should be the expected outcome:
Figure 4 – Backend service started
In the second Terminal move to the app directory (cd app) and run the command:
npm run start
This should be the expected outcome:
Figure 5 – AppRouter started
And, after a few seconds, you should see a pop-up in the bottom-right corner of Business Application Studio with a button to open the application in a new tab:
Figure 6 – Pop-up to open app in new tab
Click on that button to access the application’s index page: at this point the AppRouter will execute the OAuth 2.0 authentication flow (login) and display the index.html page:
Figure 7 – Application index page
NOTE: If you haven’t completed the post for the first and/or second approaches (directly from the HTML5 app and/or using the CAP request object) that page might look slightly different (no links for the first and/or second approaches).
Click on the “3. Using the XSUAA API” link (the /user-info/userInfoUAA() endpoint) and the user information should be displayed in JSON format like demonstrated below:
Figure 8 – Information fetched from /userinfo
As you can see, additionally to the information retrieved in the first approach, you get the BTP internal user ID, the check for e-mail verification, the user ID in the source IdP and the previous logon time. This is indeed a much richer set of information.
Using the internal BTP user ID you can get even more (such as the role collections assigned to the user on BTP) by creating an XSUAA service instance of plan apiaccess and call the /Users/{user ID} endpoint to fetch everything associated to the user in the platform – you can deep dive into this topic of Using APIs of the SAP Authorization and Trust Management Service by reading this page from the SAP Help Portal.
Conclusion
After having gone through the steps of this blog post you should have successfully fetched authenticated user information in the backend service leveraging the XSUAA API from the Authentication and Trust Management BTP service. The next step would be to try one of the other different approaches proposed in this blog posts series (if not yet done).
Please, do not hesitate to submit your questions in SAP Community through the Q&A tag link: https://answers.sap.com/index.html
Hi Alessandro,
First of thank you for this great work!
Just one minor correction from my side, the index.html link needs to be corrected as follows:
Keep up the good work!
Best,
Merve
HI Makbule Merve Gul,
Thank you for the heads-up!
The post has been updated accordingly.
Best,
Alessandro
thanks for this -
would this work in multi-tenancy mode ?
Sree
Hi Sreehari V Pillai,
I have never tested, but in theory it should work as XSUAA is a "tenant-aware" service. You just need to create the instance with "tenant-mode" as "shared" instead of "dedicated" and proceed with the usual binding.
Although the binding is done in the provider, the user info should reflect the user authenticated to the subscriber as, in the bottom line, it's just a "decoding" of the JWT token obtained during authentication.
Regards,
Alessandro
I will give it a try and post my feedback here. thanks/
S
Hi Sreehari,
Were you able to make it work with multitenancy?
Best regards,
Atakan
Hi ,
yes it worked in multi tenancy mode. Just he below
But fetching the roles failed - that might need a differ approach perhaps
Please, see the "bônus snippet" of this blog post.
Hi Alessandro ,
Thanks for this wonderful blog.
But deploying it gives us the error.
at Reading the vcap_services to fetch the XSUAA URL
Please, note that the instructions in Setup project for development are to bind the XSUAA service instance locally for development and not production.
So, have you bound an XSUAA service instance to your deployed app? If not won't even be able to authenticate to your app.
localhost:4004 is the default host for all CAP applications and should work as usual. Cloud Foundry is the one who should take care of the routing.
Just as a disclaimer: this posts series focus exclusively on the development phase. You should rely on CAP official documentation and other materials to move forward with the deployment.