Technology Blogs by Members
Explore a vibrant mix of technical expertise, industry insights, and tech buzz in member blogs covering SAP products, technology, and events. Get in the mix!
cancel
Showing results for 
Search instead for 
Did you mean: 
santhosh_kumarv
Active Contributor
In this blog let us explore how to implement OAUTH JWT Bearer Flow (i.e. using JWT as authorization grant to request access token) from SAP CPI to an Authorization server. We will use Salesforce Integration as an use case where SAP CPI acts as a client and Salesforce acts as both Authorization and Resource Server.

Salesforce has SOAP and REST API for Integration. While SOAP APIs are protected using logon session, REST API are protected using OAUTH. Salesforce supports various OAUTH Authentication Flow to enable wide range of client to the platform. JWT Bearer is one among it.

JWT Bearer Token Flow is also the recommended flow by Salesforce for server-to-server API integration. This flow can also be used to propagate identity (by user impersonation).

Before we move further in to the Implementation details I would like to list blog reference to other Salesforce Integration options.

Integration Using SOAP API

Integration Using Rest API - OAUTH Password Flow

About JWT Bearer Flow


In OAUTH an authorization grant is used by the client to obtain an access token. Several authorization grant types are defined to support a wide range of client types and user experiences.

The JWT bearer flow of OAUTH enable the client utilize an existing trust relationship(1), expressed through the semantics of the JWT(2) to acquire an access token without a direct user-approval step at the authorization server(3).

To rephrase above in the context of this blog we achieve the JWT Bearer Flow by

  1. Enabling trust between SAP CPI and Salesforce using PKI.

  2. Create a JWT token in SAP CPI and sign it with the X509 Certificate’s private key created as part of the trust.

  3. Post JWT token to Salesforce Authorization server which validates the signature using X509 Certificate created as part of trust. Successful validation yield an bearer access token.


Access token is then used during the resource call by generating header Authorization Bearer <access_token>.

Note : Access token normally expire after set duration. New access token should be fetched using JWT since this flow never issues a refresh token.

End-to-End Flow


To setup an end-to-end working flow we need to complete below 3 task.

  • Trust set-up - Between SAP CPI and SFDC

  • Main Flow    - Perform CRUD operation on Salesforce SObjects using Rest APIs

  • Token Flow  - Create an short living JWT and fetch Access Token.


This blog will circle on Trust Set-up, Main Flow and next blog on Token Flow.

Trust Set-Up


This is a two step process.

  • Generate Key pair in SAP CPI

  • Register an Connected APP in Salesforce to represent SAP CPI and associate the X.509 Certificate


Create Keypair in SAP CPI


This step is to create an certificate pair to Sign and Verify JWT.

  • From Keystore Monitor choose Create --> Key Pair.




Note : This creates a self-signed certificate pair which is sufficient but not advisable for production environment. So it's a good practice to get is signed by a CA. There is no restriction on the Certificate Authority as the certs are not used for SSL handshake like in the case of Mutual Authentication.

  • Download the public certificate(X.509) by choosing Download --> Certificate.




 

Create Connected APP in Salesforce



  • From Salesforce Classic UI Set-Up page select Create --> Apps --> New (Connected Apps)

  • Enter App Name and Check "Enable OAuth Settings"

  • Select "Use digital signature" checkbox and upload the X.509 Certificate downloaded from SAP CPI.

  • Select OAuth Scopes as shown and save the APP.




  • Upon saving A consumer key is generated. Save this in SAP CPI Secure Store as User Credential with name "SFDCClientCred".




  • Click Manage --> Edit Policy from the Connected App and configure as shown below




  • Go back to Connected APP Management UI and choose one/all the Profile (of intended users) that will use this APP.



Main Flow


Below is the snap shot of main flow. It receives an HTTP request and fetch Customer using Salesforce Rest API









































Name Description
getAccesTokenandTimeStamp

Read global variable containing access token, URL and timestamp

CheckValidity Compare access token timestamp with current time and determine it's validity.
Router 1

  • If token invalid Route to getToken branch else

  • Route to process Request default branch


callTokenFlow

  • Call Access token IFlow using Process direct adapter.

  • The invoked flow fetch token and update Global variable.


getAccessToken

Read global variable containing access token and URL into Exchange Property

setHeader

  • Set Access token in Authorization Header and

  • Instance URL in CamelHTTPUri for dynamic URL


callRestAPI

Invoke Salesforce Rest API using HTTP Adapter with Authentication as None.



The Script below to compare token and current timestamp to check it's validity is from blog HCI -Integrating SalesForce (SFDC) using HCI -Part 2 . Thanks to Bhavesh 🙂
import com.sap.gateway.ip.core.customdev.util.Message;
import java.util.HashMap;
import java.util.Date;
import java.text.SimpleDateFormat;

def Message processData(Message message) {

def propertyMap = message.getProperties()

String sessionTime = propertyMap.get("sessionTime");

// Convert sessionTime to a Calendar Date
Calendar cal = Calendar.getInstance();
SimpleDateFormat sdf = new SimpleDateFormat("dd-MM-yyyy HH:mm:ss");
cal.setTime(sdf.parse(sessionTime));

// Add 2 Hours to sessionTime
Calendar cal1 = Calendar.getInstance();
SimpleDateFormat sdf1 = new SimpleDateFormat("dd-MM-yyyy HH:mm:ss");
cal1.setTime(sdf1.parse(sessionTime));
cal1.add(Calendar.HOUR_OF_DAY, 2);

// Get Current Time
SimpleDateFormat sdfDate = new SimpleDateFormat("dd-MM-yyyy HH:mm:ss");//dd/MM/yyyy
Date now = new Date();

String sessionValid = "";

// Validate if session is Valid
if(now.before(cal1.getTime())){
sessionValid = "true";
}else{
sessionValid = "false";
}
message.setProperty("sessionValid",sessionValid);

return message;
}


 

In next blog we will look into token flow set-up.
Labels in this area