Skip to Content
Technical Articles

Get logged-in USER in SCP(CF Env) using UAA Service APIs

The availability of different environments on SCP gives us the choices for technologies, runtime, and services which allows us a lot of flexibility in our development process.

We have a service in SCP(NEO Environment) to get information about the currently logged-in user. It’s known as the UserInfo service. For more details, see How to get UserName and other login info in SAP UI5 application | SAP Blogs. This was well-documented and worked well on the NEO platform.

The simplest approach is to include UserInfo service details in the neo-app.js file, which will allow you to access user data through the application URL.

This service is no longer functional as we move towards Cloud foundry but the User Authorization and Access (UAA) or XSUAA service manages user identity while operating in a cloud foundry space. To obtain an OAuth token, the service will use the required OAuth2 flows. SAP has created a separate project to incorporate these flows due to the complexity of doing so. The App-Router checks to see if the incoming request is authenticated, and if it isn’t, it manages the exchange between the browser and the XSUAA service to log you into the application.

When a request is sent, the user information (which should always be present since all routes need a valid token) is read, and the caller’s email address is extracted and returned.

Fortunately, the following blog post by Paul Todd  will assist you greatly in this regard:

How to get the email of the logged-in user in Cloud Foundry

 

Motivation:

 The information in Neo Environment about the currently logged-in user is simple to access, appropriate, and accurate enough for its intent. However, the appropriateness and importance of the information we receive in our CF Account is not for its intended intent.

JWTs are by-value tokens. This indicate that they are data-rich. Even if you can’t see the information through your own eyes, it’s always there and easily accessible. Whether or not this is an issue is determined by the token’s intended audience.

We can start using the data from the JWT in our applications this isn’t an issue in and of itself, but it can quickly escalate if we try to alter the structure of the data in our JWT. Many integrating apps can suddenly stop working because they are not prepared for the new structure (e.g. some field missing, or change to max length of the field).

Taking these into consideration In this post, I’d like to share my work on how we can obtain logged-in USER Details in SAP CLOUD PLATFORM(CF Environment) using User Account and Authentication (UAA) Service APIs as seen in the image below.

 

Prerequisites

You need to have:

  1. A valid SAP Cloud platform account if not please follow Get a Free Account on SAP BTP Trial
  2. The Cloud Foundry command-line tools installed if not please follow Install the Cloud Foundry Command Line Interface (CLI)
  3. Editor of your choice (I use VS-code)
  4. Download the latest version of Node.js.(I personally use node v12.0.0)

A complete source code is available over here.

Let’s proceed step by step

Step 1:  Create your application

Create a new dedicated directory for your Node.js application called “cf-userinfo” and another directory inside it called “app”.

% mkdir cf-userinfo
% mkdir cf-userinfo/app

To start the application setup, change to the “app” directory and execute “npm init” in the command line. This will walk you through creating a package.json file.

% cd cf-userinfo/app
% npm init

Once the above command executed command line will ask you to provide some information to initialize your packge.json file inside your project folder. An important field is a name which you can provide “cf-userinfo”

package name: (cf-userinfo)
version: (1.0.0)
description:
entry point: (index.js)
test command:
git repository:
keywords:
author:
license: (ISC)

Now that we have initialized the project. Let’s install the app-route package using the following command:

% npm install @sap/approuter

After a couple of minutes, the package will successfully be installed and your package.json file should look like as below

Create a script file js under a directory called “app” and paste the below JavaScript code to obtain the currently logged-in user detail.

const approuter = require("@sap/approuter");
const request = require("request");
let ar = approuter();
ar.beforeRequestHandler.use("/userinfo", (req, res) => {
    if (!req.user) {
      res.statusCode = 403;res.end("Missing JWT Token");
    }
    var options = {
      method: "GET", url: req.user.token.oauthOptions.url+"/userinfo",
      headers: { Authorization: "Bearer " + req.user.token.accessToken,},
    };
    request(options, function (error, response) {
      if (error) {
        res.statusCode = 500;res.end("unavailable user information");
      };
      res.end(response.body);
    });
  });
ar.start();

Update script tag in package.json

"scripts": {
    "start": "node index.js",
    "test": "echo \"Error: no test specified\" && exit 1"
  }

Create another directory “resources” inside “app” folder for a simple HTML file called index.html. This is as basic an HTML file as possible

<html>

  <body>

    <h1>Index file of CF userinfo app </h1>

    <a href="/userinfo">current user</a>

  </body>

</html>

Create the xs-app.json file. The xs-app file is required to specify the routes for the app router.

{
  "welcomeFile": "index.html",
  "authenticationMethod": "route"
}

 

Step 2: Create XSUAA Service Instance

Create a file called xs-security.json in the main directory “cf-userinfo” and copy the following code to this file and save it.

{
   "xsappname": "cfuserinfo",
   "tenant-mode": "dedicated"
}

This file is used to set up the default roles and scopes for the user but it is not required for this app. Now create XSUAA service instance using this file. Let’s do this using the following command.

% cf create-service xsuaa application cf-userinfo-uaa -c xs-security.json

 

Step 3: Create deployment descriptor file

You must include the deployment descriptor file (manifest.yml) to deploy an application into Cloud Foundry. This file contains details about the applications to be deployed.
So next file we need to create is manifest.yml in the main directory “cf-userinfo” and copy the following resource requirements and save it.

---
applications:
  - name: cf-userinfo
    path: app
    memory: 256M
    random-route: true
    buildpacks:
      - nodejs_buildpack
    services:
      - cf-userinfo-uaa

 

Step 4: Deploy your app

Finally, it is time to deploy your application. Be in the same directory where you have created manifest.yml file and deploy the application using the following command:

% cf push

Use a random route created after a CF push to test your application.

How it works

The browser will establish a connection to the deployed application and verify that the user is currently logged in. If they aren’t, AppRouter will log you in using the OAuth flow.

When the /userinfo path is called, the user object attached to the request contains token details that are used to call the XSUAA userinfo API and return the details of the logged-in user to the caller.

3 Comments
You must be Logged on to comment or reply to a post.
  • Hello Lalit,

    The AppRouter has an User API nowadays:
    https://www.npmjs.com/package/@sap/approuter#user-api-service

    I know it doesn't support all the data fields as they hardcoded a subset, but wouldn't it be more useful to extend on that in that case? Or at least use the same logic as in that, by decoding the JWT token. This saves a call to the UAA service, but still holds all the data.

    Kind regards,

    Vincent

    • Hello Vincent,

      Thank you for your feedback. it's good to know that AppRouter now has a USER API, which will undoubtedly be more useful for the appropriate use case. I recognize that the JWT access-token contains all of the data, but we have no way of knowing how important this data is after risking decoding it. We can save a UAA service call, but when validating JWT, make sure it's being used correctly.

      Best Regards,

      Lalit