Skip to Content
Technical Articles
Author's profile photo Dries Van Vaerenbergh

Cloud Platform Integration OAuth2 Credentials

Hi Integrators,

Welcome to my Cloud Platform Integration OAuth2 Credentials blog!

Nice to have you here, it means you take security seriously.

Like we all should!

 

Introduction ?

The reason I wrote this blog is because back then, I didn’t find a lot of information or examples on how to use OAuth2 in CPI Flows.

What I really wanted to avoid was performing a request to fetch the access token and pass it throughout the CPI Flow to perform other requests.

This because it just doesn’t feel right and safe and it is not best practice at all.

Then how to handle these tokens in a proper way?

I figured out how to do it the right way thanks to: Deepak Govardhanrao Deshpande

With his very detailed and nice blog about: SAP Cloud Platform Integration – OAuth2 Client Credentials Support in OData V2 Adapter

It gave me the insight on how to use the OAuth2 credentials in CPI Flows. So thanks a lot Deepak Govardhanrao Deshpande.

Then what will I talk about?

I will show how to use this OAuth2 Credentials with 2 examples that are currently a hot topic in my option. This by showing how to use the SAP Leonardo IoT APIs and the SuccessFactors Learning (LMS) APIs.

This because they both use bearer tokens as authentication/authorization. This can be handled perfectly by the CPI OAuth2 credentials.

 

How NOT to handle your access tokens ?

Like I mentioned we do not want to “manually” fetch our tokens in our flow. If we would do this, we should start extracting it and set it as Authorization header and so on…

 

This would also bring the following disadvantages:

– The flow will get bigger

– The flow will be less clear to read

– The authorization header needs to be removed in some cases

– The token can expire

– The token can be visible in logs

– …

 

All reasons why we would not go for a solution like that.

 

 

 

How to handle your tokens ?

Then how to handle those tokens?

We store the credentials in the OAuth2 credentials in the CPI Security Material.

Once you did that you can just perform the request with the authentication type OAuth2 Client Credentials, and the tokens are taken care of automatically.

 

In the overview dashboard of your SAP Cloud Platform Integration Tenant, you go to Manage Security > Security Material.

 

Here you choose Add > OAuth2 Credentials.

 

 

 

OAuth2 & SAP SuccessFactors Learning API

How to configure the OAuth2 Credentials for the Learning API for the LMS Admin. (user also exists)

Name lms_admin_OAuth2
Grant Type Client Credentials
Description Perform LMS calls as admin.
Token Service URL https://{{YOUR-COMPANY-ID}}-stage.plateau.com/learning/oauth-api/rest/v1/token
Client ID Your client id, is the same as your company id
Client Secret Your client secret
Client Authentication Send as Request Header
Include Scope Check Checkbox
Scope { “userId”: “{{YOUR USER ID}}“, “companyId”: “{{YOUR COMPANY ID}}“, “userType”: “admin“, “resourceType”: “learning_public_api” }
Content Type application/json

 

Now you can just perform your HTTP Request without extra steps to handle the tokens.

As you can see the HTTP Request is performed on the following ITEMS URL.

(Change your company id)

The Authentication is OAuth2 Client Credentials and you provide the name you set in the Security Material.

You deploy the flow and you’ll see the flow executed successfully.

Next your SFSF Learning data is available in the logged attachment.

 

 

OAuth2 & SAP Leonardo IoT API

When you want to make use of the SAP Leonardo IoT APIS in CPI Flows, it will just work the same.

You enter your OAuth2 Credentials as follows:

Name Leonardo-IoT
Grant Type Client Credentials
Description IoT Application Enablement
Token Service URL https://{{YOUR-IoT-TENANT}}.authentication.eu10.hana.ondemand.com/oauth/token
Client ID Your client id
Client Secret Your client secret
Client Authentication Send as Request Header
Include Scope Uncheck Checkbox
Scope
Content Type

 

Again now you can just perform your HTTP Request without extra steps to handle the tokens.

Now you only need to pass an address and optional query.

Example

Address https://details-thing-sap.cfapps.eu10.hana.ondemand.com/CompositeThings/ThingType/v1/{{TENANT-PACKAGE}}:{{THING-TYPE}}/Things(‘{{THING-ID}}‘)
Query $expand=DYN_ENT_{{TENANT-PACKAGE}}__{{PROPERTY-SET}}
Authentication OAuth2 Client Credentials
Credential Name Name you provided when you set it in the Security Material. (Leonardo-IoT)

 

Execute the flow and see your flow executed successfully.

Now your IoT data is logged in the measurements and accessible in your CPI-Flow.

 

What did we learn? ?

In this blog I went over the advantages of using the OAuth2 Credentials in CPI flows.

I demonstrated the usage of OAuth2 credentials in CPI flows by making use of the SFSF Learning APIs and SAP Leonardo IoT APIs.

From now on you are able to use the OAuth2 credentials in every CPI flow you will build in the future.

 

Message of this blog?

Never pass the tokens “manually” anymore!

Thanks for reading and happy Integrating!

 

Kind regards,

Dries

 

 

Assigned Tags

      41 Comments
      You must be Logged on to comment or reply to a post.
      Author's profile photo Daniel Graversen
      Daniel Graversen

      Hi Dries,

      Great write up of how the tokens is handles.

      Is CPI able to cache the tokens or will it fetch a new one for each request.

       

      Author's profile photo Dries Van Vaerenbergh
      Dries Van Vaerenbergh
      Blog Post Author

      Hi Daniel,

      Thanks for the feedback and question.

      The way I implemented it in the examples, it will fetch a new token every time it performs the call to fetch the data.

      If I’m not mistaken, the IoT Bearer token expires every 15 minutes  by default.

      I would suggest not to cache the tokens in such a specific case, since this would bring extra validity checks with it.

      If you really would like to cache them, I think you should call the tokens manually (which I not recommend).

      But good question!

      Thanks a lot!

      Kind regards.

      Dries

       

       

       

      Author's profile photo Daniel Graversen
      Daniel Graversen

      Hi

      Yes, caching will make it more complicated to run and in most cases, it does not matter. It will probably be in high volume scenarios where a caching would make sense. It would be nice if it was on a channel level.

      Author's profile photo Dries Van Vaerenbergh
      Dries Van Vaerenbergh
      Blog Post Author

      Totally agree on that!

      Author's profile photo Philippe Addor
      Philippe Addor

      Hi both,

      Token caching is now available! (according to comment from Deepak here: https://blogs.sap.com/2018/07/31/sap-cloud-platform-integration-oauth2-client-credentials-support-in-odata-v2-adapter/)

      Best Regards,

      Philippe

      Author's profile photo Mala Bhatia
      Mala Bhatia

      Hi Dries,

      Great blog. I wanted to check if it is possible to use the OAuth2 credentials in SOAP adapter. I have a requirement where I have to send the following details in SOAP header. I tried using the OAuth2 method in both cases - SOAP and HTTP but somehow it is not working. Maybe because of the additional node - RequestHeader.

      <RequestHeader>

      <session_token></session_token>

      <client_id></client_id>

      </RequestHeader>

      Author's profile photo Dries Van Vaerenbergh
      Dries Van Vaerenbergh
      Blog Post Author

      Hi Mala,

      Thank you for your feedback!

      I do not have so much experience with SOAP myself to be honest.

      With HTTP in both of the above cases it should work fine.

      I just had a look at the authentication options with SOAP in CPI and I do not see the option:

      So as far as I can tell I do not think it is possible to use the OAuth2 Client Credentials option as Authentication.

      Therefor it is maybe not supported in the SOAP Adapter either.

      Kind regards,

      Dries

       

       

       

      Author's profile photo Bhaskar Anand
      Bhaskar Anand

      Hi Dries,

       

      How can we use EC odata Api to CPI?

      I tried but I am getting the below error:-

      Error Details
      com.sap.it.rt.adapter.sfsf.core.exception.SfsfException: Invalid type of credential provided; alias 'SF_CRED' is of credentail type 'successfactors' instead of 'oauth2:default'
      Thanks,
      Anand
      Author's profile photo Dries Van Vaerenbergh
      Dries Van Vaerenbergh
      Blog Post Author

      Hi Bhaskar,

      Thank you for your question.

      Are you trying to connect to the Successfactors OData API or to the Learning (LMS) APIs?

      In case you are trying the LMS APIs, this blog should help you.

      When you want to connect to the Successfactors APIs you could use Basic Authentication to access the SFSF OData API or OAuth.

      To me it looks like you are trying to connect to LMS with the OAuth credentials of SFSF.

      You can find out the correct API endpoint (LMS) if you follow these steps and configuration in the LMS module:

      https://apps.support.sap.com/sap/support/knowledge/public/en/2318897

      Be careful to not regenerate new client secrets if they are used somewhere else. Check with your SFSF team.

      Via the documentation above you should be able to find the correct API endpoint and you can test it via a HTTP-rest  client like Postman.

      Once you found out the correct endpoint and credentials, you can follow this blog again to retrieve your data.

      Hope this helps.

      Kind regards,

      Dries

       

       

      Author's profile photo Kiryl Kostuseu
      Kiryl Kostuseu

      Hello Dries,

      Thanks a lot for your blog! For now, I have a similar situation with manual access token setting.

      Is it possible to do that in SAP Cloud Platform Cockpit via Destination setup (cloud foundry)?

      Thanks.

      Kind regards,

      Kiryl

      Author's profile photo Dries Van Vaerenbergh
      Dries Van Vaerenbergh
      Blog Post Author

      Hello Kiryl,

      Thanks for the feedback and your question!

      I'm not sure if that's possible, if you would try to achieve this (Cloud Foundry) you would have to connect to your destination instance with your service keys and read out all your destinations and filter them on the one you need. Still, that way you would have to perform the calls to retrieve a token (on you token URL endpoint) and pass it along the CPI-Flow.

      If you want to achieve something like this I would suggest (just like the blog says) to place your OAuth URLs id's and secrets in the CPI Security > OAuth2 Credentials. Next you place the url you want to perform a call on inside your flow and you choose OAuth2 Client Credentials. CPI will take care of your authentication while your perform the request.

      I think you should implement it like this instead of using the destinations in this case.

      Hope this answers your question.

      Kind regards,

      Dries

      Author's profile photo Abhilash Kanagala
      Abhilash Kanagala

      Hi Dries ,

       

      I have followed the same process as mentioned in your blog but when I perform HTTP request  , getting response as 401 unauthorized.

      Could you let me know where I might have done mistake.

      Regards,

      Abhi

      Author's profile photo Dries Van Vaerenbergh
      Dries Van Vaerenbergh
      Blog Post Author

      Hi Abhilash,

      Thanks for your feedback and awesome you are trying it out!

      Just for my understanding, are you trying out the LMS or the IoT scenario?

      Also the first step during the debugging process of such an error, is having a look whether you can access the API’s via an http-client such as Postman.

      Via Postman you can try to retrieve your access token and once retrieved, try to get the data.

      If you cannot retrieve the data with your token, it could be something regarding user scopes or roles.

      But if you would not be able to fetch your access token, it would be probably an error with wrong credentials and the authentication payload.

      Did you try it already via Postman?

      If you can exclude this in Postman you made some progress already, otherwise it has probably something to do with the credentials and you would have to check the systems for your user credentials and access rights.

      Thanks a lot for your comment and good luck already!

      Kind regards,

      Dries

      Author's profile photo Roland Marquez
      Roland Marquez

      Hi,

      Have you ever tried connecting to Successfactors OData via OAuth2 but using “OAuth2 SAML Bearer Assertion (SuccessFactors)”?

      Any suggestions?

      Kind regards.

      Author's profile photo Dries Van Vaerenbergh
      Dries Van Vaerenbergh
      Blog Post Author

      Hi Roland,

      Thanks for your reaction.

      I did use 'OAuth2 SAML Bearer Assertion (SuccessFactors)' already but only to setup a destination in SAP Cloud Platform. (using the OData API in UI5 Applications)

      More information on how to do that can be found in the following SAP Help Documentation:

      https://help.sap.com/viewer/65de2977205c403bbc107264b8eccf4b/Cloud/en-US/55e837080eac424e8e107e18c3a8ac12.html

      If I'm not mistaken, you could setup your “OAuth2 SAML Bearer Assertion (SuccessFactors)” in CPI and just consume it in your flow using the "OAuth2 SAML Bearer Assertion" option as authentication.

      I never tried it myself, but it would be my first approach.

      Hopefully it can be of use.

      Best regards,

      Dries

      Author's profile photo Vineet Vivekanand Kulkarni
      Vineet Vivekanand Kulkarni

      Hi,

      Is it possible to pass optional parameters?

      It looks something like this with JAVA code:

      Map<String, String> optionalParameters = new HashMap<>();optionalParameters.put("response_type", "token");
      optionalParameters.put("authorities", "{\"az_attr\":{\"ZoneID\":\"AN02002005169\", \"external_id\":\"abcd1234\"}}");OAuth2TokenService oAuth2TokenService = new XsuaaOAuth2TokenService(new RestTemplate());
      String access_token = oAuth2TokenService.retrieveAccessTokenViaClientCredentialsGrant(
      URI.create(tokenURL), new ClientCredentials(clientId, clientSecret), null, optionalParameters,true).getAccessToken();

       

      Kindly advice if in security material something like this can be maintained for the optional parameters with OAuth apart from client id and client secret.

       

      Thanks and Regards,
      Vineet.

      Author's profile photo Dries Van Vaerenbergh
      Dries Van Vaerenbergh
      Blog Post Author

      Hi Vineet,

      Thank you for your interesting question.

      To be honest I have no idea, the only thing I know is that you can pass a scope along with the OAuth2ClientCredentials. But I guess that's not what you are looking for here.

      Best regards,

      Dries

      Author's profile photo Christine De Leon
      Christine De Leon

      Hi Dries,

      Thank you so much for this blog!

      I just wanted to ask if the same approach applies in Onboarding API? I tried the ONB ODataAuthentication API via Postman and I was able to get the Token.

      I’m trying to do the same in CPI using HTTP connector via Basic Authentication but was getting this error:

      org.apache.camel.component.ahc.AhcOperationFailedException: HTTP operation failed invoking https://<my data center>/ONB/odata/v2/ODataAuthentication with statusCode: 400

      Thank you in advance!

       

      Kind regards,

      Christine 

       

       

      Author's profile photo Dries Van Vaerenbergh
      Dries Van Vaerenbergh
      Blog Post Author

      Hi Christine,

      Thank you for your reaction!

      I'm not really sure but I believe the OAuth 2 Client Credentials do not apply here.

      Did you already try the request via an OData Adapter? Or even the Successfactors Adapter with the user credentials in the the Security Material of you CPI environment? (maybe of the type SuccessFactors)

      I did not try it myself yet with this authentication mechanism.

      I hope this can be a little bit helpful. 🙂

      Best regards,

      Dries

      Author's profile photo Shruthi Anantha
      Shruthi Anantha

      Hi Dries,

      Very Informative blog.

      I have a requirement to read Successfactors EC data using OAuth.But I think it is still not supported for a timer based Integration.

      Can we get data from Successfactors using HTTP Adapter and use OAuth Client Credentials for that user?

      Can you let me know how should the OAuth Client Credentials be configured in CPI?

      Author's profile photo Dries Van Vaerenbergh
      Dries Van Vaerenbergh
      Blog Post Author

      Hi Shruthi,

      Thanks for your feedback!

      I believe using OAuth would be possible and it would be very similar to the "OAuth2 & SAP SuccessFactors Learning API" example in this blog.

      When you provide the "token url", "client id" and "client secret" and use the configuration on the HTTP Adapter it should work I guess. I'm not sure wether the SFSF API requires a scope.

      But I believe that should do the trick.

      Best regards,

      Dries

      Author's profile photo Dinesh M
      Dinesh M

      Hi Dries,

      What is the difference between 'Send As request Header' or 'Send as Request Body' in client Authentication

      Thanks in advance,

      Dinesh

      Author's profile photo Philippe Addor
      Philippe Addor

      Hi,

      Based on the way OAuth2 token service requires the client ID and secret to be sent as part of request, select the one relevant:

      1. Send as Body Parameter: Sends client ID and secret as request body in JSON format
      2. Send as Request Header: Sends the client ID and secret as part of the request header

      Regards,

      Philippe

      Author's profile photo Sudeep Menakuru
      Sudeep Menakuru

      Hi - What if the token is generated based on client id and secret in body parameter and the token is expected to be sent in header parameter with bearer string prepended to it? How can this be achievable?

      Author's profile photo Philippe Addor
      Philippe Addor

      Hi Sudeep, what you describe is the standard behaviour of the Oauth2 flow. A bearer token is usually sent as HTTP header with prefix "Bearer". That's what CPI does here too, regardless of the mentioned options for the client ID/secret (which is only for the first step, to fetch the token, not the send it in the final request).

      Author's profile photo Ipshita Lahiri
      Ipshita Lahiri

      HI,

      Thanks for the great blog.

      I want to understand if we can pass grant_type=password to fetch the token like we do in POSTMAN. I would need this configuration as I am getting a 403 error when using oauth 2.0 with client credentials. Our APIs are protected with certain roles and I would need to pass the userID and password to get it working in CPI. The same works fine in POSTMAN when I make a POST call to the authentication URL by passing the userID and password in the request body.

      Best regards,

      Ipshita Lahiri.

      Author's profile photo Yves Pittino
      Yves Pittino

      Hello,

      I guess in that case SAP does not provide a solution with OAuth Credentials. We have to fall back to Groovy scripts what the blog just does not want us to do.

      Any comments Dries?

      Best Regards, Yves

      Author's profile photo Gregor Wolf
      Gregor Wolf

      Hi Ipshita Lahiri,

      what solution did you implement to solve the OAuth grant_type=password flow? As described in SAP Note 3015211 - BASIC authentication options for SAP BTP Cloud Foundry applications that would be the way to to get a token via Password Grant from the XSUAA even with a Custom IAS instance and use this token to authenticate to a CAP application.

      Best Regards
      Gregor

      Author's profile photo Gregor Wolf
      Gregor Wolf

      To move this topic forward I've filed an SAP Influencing Idea:

      293686 Add support for the OAuth Password grant to support outgoing connections to BTP Applications

      Please vote :-).

      Author's profile photo Timmy Becker
      Timmy Becker

      Hi Gregor,

       

      thanks. Voted for it already.

      BR.

      Author's profile photo Gaëtan Broutin
      Gaëtan Broutin

      Hi,

      one of the system I need to integrate with needs additional parameters in the body (Content-Type: application/x-www-form-urlencoded).

      In addition to the scope, I need an additional parameter "client_id" which is not the same ID as the client ID corresponding to the secret. In postman it looks like this (and working):

      Example with fake data

      Request Headers
      Accept: application/json
      Content-Type: application/x-www-form-urlencoded
      Authorization: Basic ZTNMS97767asdfdFSrkdfgjdfklghioewSIDJIOJezruwierFDSF
      User-Agent: PostmanRuntime/7.26.8
      Postman-Token: xxxxxxx-xxxx-4adb-xxxx-1c9353c25288
      Host: apis.staging.xxxx.com
      Accept-Encoding: gzip, deflate, br
      Connection: keep-alive
      Content-Length: 89

      Request Body
      grant_type: "client_credentials"
      client_id: "ffffffff-ffff-ffff-ffff-fffffffffff"
      scope: "client"

      Do you have any idea?

      Thanks in advance

       

      Gaetan

      Author's profile photo Arthur Parisius
      Arthur Parisius

      Hello Gaëtan,

       

      Did you come to a solution for this?

      I'm having a similar issue for a customer custom connection.

      I did the set-up as described in the blog but when testing I get an error stating that the request body needs the grant_type parameter and the problem is that the client is apparently unable to give me what other parameters I might need.

      Author's profile photo Gaëtan Broutin
      Gaëtan Broutin

      Hi Arthur,

      unfortunately I still could not find any SAP-Standard Element for my use case.

       

      What I do is that I am fetching the token separately using an HTTP Call:

      Step 1: Prepare Body including the client_id parameter

      Step 2: Do the API Call to get the Bearer Token (Using "User Crentials" with application-id as username and application secret as password in the security meterial)

      Step 3: Extract the Bearer Token from the json response body

       

      I do not really like this method as your temporary Bearer token is in clear if you are in trace mode and inspect the flow but unfortunately I could not find a better way...

      If you plan to use the "get token" across multiple flows you might also want to create a separate flow to get the token and call this flow from your other flows using Process Direct (for this you have some ressources on the blog platform from SAP)

      Author's profile photo Tikeer Guo
      Tikeer Guo

      Thank you for your sharing, it is interesting and useful.

      Author's profile photo Mike Buono
      Mike Buono

      WORKED GREAT!!

      FYI - Encountered an issue when deployed, error states

      "Error in retrieving Authorization header, cause: com.fasterxml.jackson.core.JsonParseException: Unexpected character".

      Found that when I did the copy/paste of the Scope syntax in the main article for the LMS OAuth2 credential, the text came through with the fancy, curly double-quote or speechmark symbol ", instead of the unformatted version, "

      Try this:

      { "userId": "{{admin_account}}", "companyId": "{{company_ID}}", "userType": "admin", "resourceType": "learning_public_api" }
      Author's profile photo Dries Van Vaerenbergh
      Dries Van Vaerenbergh
      Blog Post Author

      Hi Mike,

      Happy to hear it worked out well! 🙂

      Also thanks for sharing the format issue as well!

      Best regards,

      Dries

      Author's profile photo Sudeep Menakuru
      Sudeep Menakuru

      Hi - What if the token is generated based on client id and secret in body parameter and the token is expected to be sent in header parameter with bearer string prepended to it? How can this be achievable?

      Author's profile photo Kenrick Chan
      Kenrick Chan

      Hi Dries,

      I set a security material up as follows and run the iflow but it errors out. Did I miss something? Any clue provided will be most appreciated. Thanks.

      com.google.common.util.concurrent.UncheckedExecutionException: java.lang.IllegalArgumentException: Exception occured while fetching OAuth Token. Reason: sun.security.validator.ValidatorException: PKIX path building failed: sun.security.provider.certpath.SunCertPathBuilderException: unable to find valid certification path to requested target, cause: sun.security.provider.certpath.SunCertPathBuilderException: unable to find valid certification path to requested target

      Author's profile photo Philippe Addor
      Philippe Addor

      Your CPI tenant is missing the root/intermediate SSL certificates of the target server. Simply download them using TLS Connectivity Test and upload them to the key store.

      Author's profile photo Federico Espinas
      Federico Espinas

      What are some common challenges that users might face when implementing OAuth2 credentials in CPI flows, and how can they be overcome?

      Author's profile photo Philippe Addor
      Philippe Addor

      What's the aim of your question? I would say all the comments above should give you some answers.