Skip to Content
Author's profile photo Florian Pfeffer

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.

Assigned Tags

      26 Comments
      You must be Logged on to comment or reply to a post.
      Author's profile photo Mahmoud Kassem
      Mahmoud Kassem

      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.  

      Author's profile photo Todor Petrov
      Todor Petrov

      Hi Mahmoud,

      I am facing a similar issue, can you please specify what you changed to make it work.

      Thanks,

      Todor

      Author's profile photo Prudhvi Kolipaka
      Prudhvi Kolipaka

      Hi Todor,

      if you have a Custom IAS tenant configured to the sub account, make sure both default and custom IAS tenants are marked as active in BTP cockpit->security->trust configuration.

      Because by default, it will try to authenticate using SAP.IDS and if it is marked as inactive, it will throw unauthorized issue.

      Author's profile photo Denise Nguyen
      Denise Nguyen

      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

      Author's profile photo Fabio Ferrari
      Fabio Ferrari

      Hi Denise, I have the same issue. Did you find any solution?

       

      Thanks and BR,

      Fabio

      Author's profile photo Arun Muthukumarasamy
      Arun Muthukumarasamy

      Hi Denise,

      Were you able to resolve this issue I’m also facing the same issue? Kindly update if you found the solution.

      Regards,

      Arun

      Author's profile photo Rakshetha J N
      Rakshetha J N

      hi any updates on getting the token when we use SAML / SAP ID service .

       

      best regards

      rakshetha

      Author's profile photo Subash Mohanmurugan
      Subash Mohanmurugan

      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.

      Author's profile photo Tillmann Radmer
      Tillmann Radmer

      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.

      Author's profile photo Priyanka Sadana
      Priyanka Sadana

      I am still facing this issue. Any highlight on how to resolve it?

      Florian Pfeffer : Great blog!

      Author's profile photo Fabian Bahle
      Fabian Bahle

      Hi Priyanka,

      I'm also still facing this issue, even with URI encoded parameters and correct credentials. Did you manage to fix it?

       

      Kind regards,

      Fabian

      Author's profile photo Arpit Kumar
      Arpit Kumar

      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

      Author's profile photo Brian McDonnell
      Brian McDonnell

      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

      Author's profile photo Binson Varikkasseril Abraham
      Binson Varikkasseril Abraham

      Hello,

       

      password grant_type is not supported with custom IdP, as documented at https://launchpad.support.sap.com/#/notes/2766354

       

      Regards,

      Binson

      Author's profile photo Brian McDonnell
      Brian McDonnell

      Binson,

      Thank you for the response. My mistake for not checking SAP Notes and instead thinking this sort of thing would be documented within the publicly accessible documentation. Always difficult when there are multiple sources of documentation!

      Thanks,

      Brian

      Author's profile photo SANDEEP TDS
      SANDEEP TDS

      The blog is amazing! Thank you so much.

      Author's profile photo Shashank Kulshrestha
      Shashank Kulshrestha

      Excellent post! very helpful and precise!

      Author's profile photo André Gruhn
      André Gruhn

      I have extended the OAuthClient to also use client credentials flow:

      https://gist.github.com/scanacs-awuttig/0f1249e279690be97c297110b37d5e10

       

      Author's profile photo Satish Kumar Kara
      Satish Kumar Kara

      can i generate a GWT?

      Author's profile photo Rajdeep BHUVA
      Rajdeep BHUVA

      Hi,

       

      Great Blog!

      Can i generate token by providing user name and password rather providing client id and client secret with custom IDP service?

       

      Thanks,

      Rajdeep Bhuva

      Author's profile photo Francesco Pisano
      Francesco Pisano

      Hi Rajdeep,

      have you finally found how to gen token by providing user name and password? I have the issue.

      Author's profile photo Rajdeep BHUVA
      Rajdeep BHUVA
       If you are using Custom IDP service then you can not generate token by User ID and password. You need to use Client ID and Client secret.
      Thanks,
      Rajdeep Bhuva
      Author's profile photo Francesco Pisano
      Francesco Pisano

      Ok Rajdeep,

      but in my situation i need to gen token using password credential. I see in many blog that is not possible due to custom IDP not support it. Do you know if exists a possible solution that avoid this problem?

      Tnks

      Francesco

      Author's profile photo Rajdeep BHUVA
      Rajdeep BHUVA

      Hi Francesco Pisano   ,

      Sorry, No solution exists.

      You can pass userID in parameter with encoded value and make it somewhat level difficult and achieve it.

       

      Thanks,

      Rajdeep Bhuva

      Author's profile photo Rachel Banas
      Rachel Banas

      Hi Florian Pfeffer ,

       

      When i tried to send the POST request, there was no access token returned.

      Initially i had bad credentials error returned and i solved it by EncodeURIComponent as suggested above.

      However now, this was the return:

       

      Would you know what could've possibly been missed?

      Thank you very much.

      Author's profile photo Surve Pooja
      Surve Pooja

      Hello Florian Pfeffer ,

      Thanks a lot for this guide!

      Everything worked fine for me as long as I was working with Postman. When I tried to consume the API in a chatbot with URL https://xyz.dev.azure.com, I got error 403 for POST call for getting the access token.

      Basically, the error was for the preflight call.

      Can you suggest what needs to be fixed?

       

      Thanks & regards,

      Pooja Surve