Skip to Content

How to get an access token from the XSUAA Service for external API accesses using the Password Grant with Client and User Credentials method

Introduction

Recently in the community a question was asked how an access token can be determined to access a XSUAA secured SAP HANA XS Advanced service (e.g. written in Node.js) directly from an external application. I think I gave a very detailed answer to that question, but I wanna write it down here also in a blog post, because there are some steps necessary to be able obtain an access token via the XSUAA API. As said in the title, the “Password Grant with Client and User Credentials” method is used and described in the following lines. Details about the API interface can be found in the official Cloudfoundry UAA documentation.

In summary following steps are necessary:

  • Determine client credentials for XS Advanced service application.
  • Determine the XSUAA server URL.
  • Obtain an access token from the /oauth/token endpoint of the XSUAA server.

For test reasons I created a simple MTA application containing an Node.js module with a test endpoint returning a simple JSON object containing a “success” property to indicate that the call was successful.

{
  "success": true
}

The application is secured by an XSUAA service instance. A user who wants to access the endpoint need the scope “Display”. This scope is assigned to my test user via a role collection. In case you want to try it out by yourself you can clone my test repository xsa-access-api-from-external, create the XSUAA service either via CLI or the XSA Cockpit using the xs-security.json file, deploy the test application, create a role collection containing the created roles and assign the role collection to your test user.

In my case I deployed the application to the development space on a HANA express edition instance.

Determine the XSUAA server and the client credentials

Before an access token can be requested it needs to be known where the token can be requested. It is also necessary to know the client id and client secret for the application we deployed before. Both information can be found in the environment variables of the application in following properties:

  • VCAP_SERVICES.xsuaa.credentials.clientid
  • VCAP_SERVICES.xsuaa.credentials.clientsecret
  • VCAP_SERVICES.xsuaa.credentials.url (XSUAA server url which provides the required access token endpoint)

The environment variables for an application can be determined either via the XS CLI or within the XSA Cockpit. Pre-condition: Application is deployed and XSUAA service is bound to the application.

To get the environment variables via the XS CLI for my test application with the name IqdL0TY2Av5-jlbDnal-access-api-js deployed in the development space the XS ENV command is called which produces following output.

In the XSA Cockpit the same information can be found in the Service Bindings area for an application. Marking the XSUAA service binding and pressing “Show sensitive data” displays the required information

Determine access token

After all required information is determined an access token can be requested by doing a POST request to the /oauth/token endpoint for the XSUAA server URL. In that test here the complete URL is http://hxehost:39032/uaa-security/oauth/token.

For test reasons Postman is used to simulate the client. As seen on the next image for the request the following headers have to be set:

  • Accept: set to application/json;charset=utf8 to indicate that the client accepts a JSON response
  • Content-Type: set to application/x-www-form-urlencoded to define that the payload contains form-url-encoded values

The payload of the request needs to have following form-url-encoded values:

  • grant_type: set to password to define that the client and user credentials method has to be used for the token determination
  • username: set user name of authorized user
  • password: password of the authorized user
  • client_id: the client id determined for the application
  • client_secret: the client secret determined for the application
  • response_type: set to token to indicate than an access token is requested

After a successful call with correct user and client credentials an access token is returned in property access_token. The scope property contains also the Display scope (external-api-access.Display = application name + scope) which is assigned to the user via the role collection containing the relevant role.

Positive API access test

With the access token it is possible to access the test API. The test API endpoint is available at end point /api/testEndpoint for the deployed Node.js application. In that case the full URL is https://hxehost:51047/api/testEndpoint. In case you try the example by yourself check the application URL you got either in the XSA Cockpit (application section) or via the XS APPS command.

For the executed GET request again the Accept header is set to indicate that a JSON response is expected. The more important header is the Authorization header which has to be set in form “Bearer <access token>”.

Executing the request will result in getting the expected JSON object.

Negative API access test

To show that the access token really works and is not just a fake the access token in the header is set to something different than the access token provided by the UAA server.  Adding e.g. a “XX” in front of the access token in the header results in a 403 Forbidden result.

Conclusion

I hope this helps a little bit in case someone wanna access an XSA deployed service via an access token from another external application. Please also check the above linked official Cloudfoundry UAA documentation for more details and options.

16 Comments
You must be Logged on to comment or reply to a post.
  • Hi Florian,

    first off thank you for this blog it is rather hard to find resources about the topic in the XS a context. And as a disclaimer I’m pretty new to this stuff. I followed the flow with our XS advanced application and got an access token in Postman, but I’m unfortunately getting a 403 error:

    {
        "error": "insufficient_scope",
        "error_description": "Insufficient scope for this resource",
        "scope": "uaa.admin uaa.user"
    }

    which I find strange I was assuming that having the $XSAPPNAME.Display scope would suffice.

    I’m also wondering if the xsuaa is the IdP in your scenario, is that even possible? What I’m curious about is wether the username and password that are passed in the POST call also live in the xsuaa or in an exernal IdP(which is our scenario).

    EDIT:

    It is resolved now the issue was actually sitting in front of the computer. I was trying to access the wrong endpoint namely the application router, which requires more scopes. Using the access token to access the js module directly yielded the expected result.  

  • Hi Florian,

    Thank you for this blog post. It’s very useful for me.

     

    When I try to post to /oauth/token, I get the error:

    {
    “error”: “unauthorized”,
    “error_description”: “Bad credentials”
    }

     

    I guess it’s because we configure to use SAML with the xsuaa. Could that be the reason that I can’t get the token ? If yes, do you have any suggestion how we can get the access token ?

     

    Thank you for your help,

    Best regards,

    Denise

        • Hello Everyone,

          This access token retrieval was working fine for me and suddenly I started facing this unauthorized error.

          Later, I figured out that my username is wrong.

          Three things to pay attention,

          1. From account cockpit, make sure your i_no is a member of that particular subaccount
          2. Use only email address and not the i_no for authorization
          3. look for typo in email or password

          Kind regards,

          Subash.

    • Hello,

      I was getting the same error message

      {
          "error": "unauthorized",
          "error_description": "Bad credentials"
      }

      For me the issue was that I didn’t URL encode the parameters in Postman. To do so do the following:

      1. select all text of the value field of the parameter that you want to encode in Postman
      2. right-click the value field with the selected text and click on “EncodeURIComponent”

      That will encode special characters like for example “@” in the email for sending in an URL parameter.

      After that it worked out.

  • Can you help in achieving the same with OAuth+SAML Bearer token? There is one document about SCP Neo to SCP CF – but in our case we are using some other application and struggle with the option of SAML Assertion

  • Hi Florian,

    Thank you for providing this example.

    One question I have is how does this work with multiple IdPs? I had difficulty getting this to work with a proper username/password using my own custom IdPs (each provided through the SAP Identity Authentication Service (IAS)) and only had success when re-enabling the default SAP ID Service. Is there some other type of value that can be passed into the request to ensure those other identity stores are taken into account?

    **Edit**

    I looked at the CF UAA Documentation for password grant and they list a parameter that covers my question exactly. The documentation describes the parameter login_hint saying it Indicates the identity provider to be used. I’ve tried using this in my token request and it appears to have an (unsuccessful) influence on the response. Here’s what I’m seeing when it’s included:

    {
    "error": "unauthorized",
    "error_description": "The origin provided in the login_hint does not match an active Identity Provider, that supports password grant."
    }

    Based on the error I’m thinking the problem here is that a typical SAP IAS IdP does not support password grant out-of-the-box. So far I haven’t found any configuration options to enable this.

    Any insight on how I might work around this? One lead I’m considering chasing is using OpenID Connect within the SAP IAS but I haven’t found how that can be used in SAPCP CF Subaccount Trust Configuration. 

    Thanks,

    Brian