Technical Articles
Show current user details in Cloud Foundry apps with IAS
It’s always nice to show the name of the user in your app. Doing this in SCP applications requires a different implementation on CF compared to NEO. SAP provides a service for this in NEO but not in CF. Luckily, the following blog post helps a lot with this:
https://blogs.sap.com/2019/05/23/how-to-get-the-email-of-the-logged-in-user-in-cloud-foundry/
I tried this post and it works perfectly when using the default IDP from SAP but once you’re using your own IAS, it only shows the userid:
Although it can be solved easiIy it took me some time to find a solution. Therefore I’m sharing how to solve this. I came up with several solutions to fulfill all possible needs.
Solution 1: Changing the userid to mail, login name or something else.
In the first solution, I’m just going to change the userid to the mail of the user. I’m using mail as an example but their are other possibilities too, like login name, display name , … .
Changing this will be done in the IAS for the related application by following the next steps:
Go to your IAS -> open “Applications & Resources” -> “Applications”
Open the right application configuration -> Trust -> Click on “Subject Name Identifier”
Here you can change the attribute to the one that you want to display in your app. By default the IAS is using the User ID. This can be changed E-Mail, Display Name or anything you like in the provided list:
After changing to E-Mail you will get the mail address in the “getuserinfo”. (Like mentioned earlier, I’m using this blog for the implementation of “getuserinfo”: https://blogs.sap.com/2019/05/23/how-to-get-the-email-of-the-logged-in-user-in-cloud-foundry/ )
Display name will show the following:
You can also use “Advanced Configuration”. This will allow you to add a prefix and a suffix to the attribute but you can only use one attribute here.
You can find a list of possible attributes in SAP help:
Solution 2: sap-xssec library
The previous solution is an easy solution to switch the userid to the mail address or even the login name. In case you want to show more information of the user this is still not the ideal solution that you’re looking for. This solution will provide you a bit more information of the user next to the “Subject Name Identifier” from the IAS.
For this solution I’m using the sap-xssec library to get the user info. You can find more information of this here:
I also use the sap-xsenv library to get the xsuaa service:
Add the library to the dependencies in the package.json:
Add the following code to the “approuter-start.js” script. I wrapped the xssec createSecurityContext in a promise in a separate function to use it in the “beforeRequestHandler”:
This will give you a lot of information including the userinfo:
In normal situations we would only expose the userinfo and not all the other details. This is just for testing purpose to know what’s in the “securityContext” object.
Credits for this one go to John Patterson and Vincent Weiss !
Solution 3: Use JWT token to get more information of the user
This solution will provide similar information as the previous one but by just decoding the JWT token. Credits go to Dries Van Vaerenbergh for this one!
For decoding the JWT token I’m using the following npm package: “jwt-decode”
https://www.npmjs.com/package/jwt-decode
By including the package in your script and just one line you get more information of the user out of the JWT token: (full code project: https://github.com/lemaiwo/AppRouterUserInfo )
const jwtDecode = require('jwt-decode');
var decodedJWTToken = jwtDecode(req.user.token.accessToken);
This will give us the following information about the user:
Solution 4: Get all user details from IAS
Last but not least, if you really need all the information of the current user you can get it from IAS. This can be done by using the API from the IAS:
Before using this API, you need enable the API authentication of your application in the IAS. You can also find this in the SAP help: https://help.sap.com/viewer/6d6d63354d1242d185ab4830fc04feb1/Cloud/en-US/9ea13fe831e24620bc89affab178ff93.html
Go to your IAS, select the correct Application:
In the first tab you scroll down to API Authentication and click on “Client ID and Secrets”:
If not yet done, create a new secret. In case Client ID was empty, adding the first secret will generate one:
Here an example of getting the user information by using the email address in postman. For authentication we use the client id and secret:
If you want to use this API in our app you need to be aware that it’s not possible to do this directly in the UI because of security reasons. Even with a destination the API will force a redirect which will be blocked by CORS policy. For that reason, it needs to be implemented on the server side like for example in a nodejs or Java middleware. An easy way could be to implement it in the same function of the approuter that we’re using already.
Besides enabling the API Authentication, you also need to create a destination in the SCP platform. Go to you subaccount → Destinations and create a new destination to the IAS
Use client id and secret in destination:
Next add the following code in the function “beforeRequestHandler” of the approuter:
Full code: https://github.com/lemaiwo/AppRouterUserInfo/blob/master/approuter-start.js
rp({
uri: uaa_service.credentials.url + '/oauth/token',
method: 'POST',
headers: {
'Authorization': 'Basic ' + Buffer.from(sUaaCredentials).toString('base64'),
'Content-type': 'application/x-www-form-urlencoded'
},
form: {
'client_id': dest_service.credentials.clientid,
'grant_type': 'client_credentials'
}
}).then(function (data) {
const token = JSON.parse(data).access_token;
return rp({
uri: dest_service.credentials.uri + '/destination-configuration/v1/destinations/' + sDestinationName,
headers: {
'Authorization': 'Bearer ' + token
}
});
}).then(function (data) {
const oDestination = JSON.parse(data);
const token = oDestination.authTokens[0];
return rp({
method: 'GET',
uri: oDestination.destinationConfiguration.URL + sEndpoint + req.user.name,
headers: {
'Authorization': `${token.type} ${token.value}`
}
});
}).then(function (xmldata) {
parseString(xmldata, function (err, IASResult) {
res.end(JSON.stringify({
name:req.user.name,
user: req.user,
decodedJWTToken: decodedJWTToken,
iasData: IASResult
}));
});
}).catch(function (error) {
res.end("error: " + JSON.stringify(error));
});
This code is based on the example of Marius Obert in his blog about the Destination Service in Cloud Foundry: https://blogs.sap.com/2018/10/08/using-the-destination-service-in-the-cloud-foundry-environment/
When running this service after deploying, you will get not only the first and lastname but also address information and everything else that’s filled in on IAS:
User information on IAS:
Full project with all code of all solutions can be found on GitHub: https://github.com/lemaiwo/AppRouterUserInfo
Hope this will help you!
Greetings, Wouter!
Thanks for sharing the blog Wouter Lemaire.
This helped a lot. Just wanted to check is there any API in IAS to update any profile attribute from application. Like if I want to edit my mail id from UI5 application & I want to update IAS with the updated mail id. How can this be achieved ? Do you have any reference please ?
Cheers.
Have you tried this one? https://help.sap.com/viewer/6d6d63354d1242d185ab4830fc04feb1/Cloud/en-US/9e36479e92ca4b0db75f085d4ab3aa23.html
Thanks for sharing this blog Wouter Lemaire. . It is quite explanatory and helpful.
While following the details, one question came to my mind which I would like to share.
You have mention that in a custom IDP (IAS Tenant) in CF, we can set "Subject Name Identifier" as User ID and same can be fetch from JWT token. But if the application is using SAP default IDP, SAP ID service, this will be email id always. Also in the JWT token we se email id as user id. My question is , is there a way we can get user id (C/D/I number) from the email ID when using default IDP in CF ?
It will be great to have your suggestion. Many thanks..
Cheers,
Subh
Hi Wouter Lemaire. ,
Thanks for this great blog.
I was able to implement solution 3.
In my current project development, i am using Cloud Application Programming Model where i am trying to get the similar details in my node.js layer of SRV. I tried using req.user.attr which says it will give us SAML attributes, however its not returning anything. Is there any way we can get similar details like this in CAP model SRV JS layer ?
Thanks,
Mahesh Z
There is a new user api in the approuter which might help you https://blogs.sap.com/2021/02/20/sap-tech-bytes-approuter-user-api-service/
regarding the user attributes in cap, not sure why you don’t get the attributes. Maybe something wrong in the sso config?
Hi Wouter,
Thanks for sharing this useful information.
Can you please advise how can we implement Solution 2 or Solution 3 in a Fiori app with Managed Approuter in CF as in the package.json, it doesn't call the standard approuter.js which we can extend to use sap-xssec library or jwt token.
.
Regards,
Arjun
This is not possible with the managed approuter. It requires custom dev while you cannot extend the managed approuter.
Hi Wouter,
Thanks for your response.
Is it possible to switch approuter configuration from managed to standalone for a MTA project? Any idea?
Regards,
Arjun
Hi Wouter,
Is there a way to access the decoded jwt tokens to find Assertion attributes passed from IDP in an application with Managed Approuter? Like calling the api from a destination?
We have to use Managed approuter as apps are deployed on Portal. Using Standalone approuter causes issue in that we cannot use Shell services and Theming in apps etc.
Regards,
Kaustubh