Wednesday, January 9, 2019

Salesforce to Salesforce integration using Client Credentials Flow

Let say I have two Salesforce org say ORG A and ORG B. Our requirement is whenever Account record is created in Salesforce ORG A and when certain conditions are meet we need to create the same Account record in ORG B. The integration between ORG A and ORG B should be done using client credential flow.

Let's start,

ACTIVITIES WE NEED TO DO IN ORG B.

1) Create a Connected App in ORG B.

2) Create a Webservice in ORG B which will be invoked from ORG A to create the contact record.

Create A Connected App In ORG B:

Configure a connected app as shown below in ORG B and Click Save.

Salesforce to Salesforce integration using Client Credentials Flow

Salesforce to Salesforce integration using Client Credentials Flow

Select Enable Client Credentials Flow as shown below.

Salesforce REST API create record

Note down the Consumer key, Consumer secret (We need to provide it to ORG A for authentication).

A callback URL is the URL that is invoked after OAuth authorization for the consumer (connected app). In some contexts, the URL must be a real URL that the client’s web browser is redirected to. In others, the URL isn’t actually used, but the value between your client app and the server (the connected app definition) must be the same. Here we are providing the URL of ORG A in the format as asked in comment for Callback URL.

Although there’s no user interaction in the client credentials flow, Salesforce still requires you to specify an execution user. By selecting an execution user, you allow Salesforce to return access tokens on behalf of this user.

From the connected app detail page, click Manage.

Click Edit Policies.

Under Client Credentials Flow, for Run As, click Magnifying glass icon, and find the user that you want to assign the client credentials flow.

Salesforce to salesforce integration using client credentials flow example

Create A Webservice As Shown Below In ORG B:

Now, create a Webservice as shown below in ORG B.

The below Webservice is expecting Name, Description, Type, Industry and is creating an Account record and is returning True or False based on if Account record is created successfully or not.

@RestResource(urlMapping='/createAccountRecord/*')

   global with sharing class createAccountRecord {

     @HttpPost

      global Static string createAccount(){

      RestRequest req = RestContext.request;

      RestResponse res = Restcontext.response;

      string jsonString=req.requestBody.tostring();

      system.debug('jsonString'+jsonString);

      boolean successCheck;

      List<responseWrapper> wRespList=(List<responseWrapper>) JSON.deserialize(jsonString,List<responseWrapper>.class);

      Account obj=new Account();

      List<Account> accList= new List<Account>();

      for(responseWrapper wResp: wRespList){

      obj.Name=wResp.Name;

      obj.Description=wResp.Description;

      obj.Type=wResp.Type;

      obj.Industry=wResp.Industry;

      accList.add(obj);

      }

      try{

      if(accList.size() > 0){

      Insert accList;

      successCheck=true;

      }

      }

      catch(Exception e){

      successCheck=false;

      }

      if(successCheck)

      return 'Success';

      else

      return 'Failure';

      }

      global class responseWrapper{

       global string Name;

       global string Description;

       global string Type;

       global string Industry;

      }

   }

ACTIVITIES WE NEED TO DO IN ORG A.

1) Create an apex trigger and apex controller.

2) Create a remote site setting for the URL of ORG B.

Create a custom metadata to store the Consumer key, Consumer secret provided by ORG B as shown below.

salesforce oauth 2.0 client credentials flow for server-to-server integration

Now, create a record under the above custom metadata as shown below.

salesforce oauth 2.0 client credentials flow for server-to-server integration

 APEX TRIGGER IN ORG A:

The below apex trigger will be invoked after Account record is inserted in ORG A and it will call controller created in ORG A if Account Type is not null and equal to Prospect and this apex controller will further call Webservice in ORG B to create the same Account record.

trigger Accounttrigger on Account (after insert) {

    Set<id> accIdSet=new Set<id>();

    for(Account acc:trigger.new){

        if(acc.Type!=Null && acc.Type=='Prospect'){

            accIdSet.add(acc.id);

        }

    }

    if(accIdSet.size() > 0){

        restApiToCreateRecord.createAccount(accIdSet);

    }

}

CREATE AN APEX CONTROLLER:

Now, create an Apex controller which will call Webservice in ORG B. This apex controller method will be invoked from apex trigger created above.

public class restApiToCreateRecord {

 

    private string cKey;

    private string cSecret;

    private string uName;

    private string passwd;

    public string instanceURL;

    public restApiToCreateRecord () {

      

    }

    public class responseWrapper {

        public string id;

        public string access_token;

        public string instance_url;

    }

    public responseWrapper getRequestToken() {

        List < Store_Cred__mdt > connectionParam = [SELECT Id, MasterLabel, client_id__c, client_secret__c, username__c, password__c from Store_Cred__mdt];

        if(connectionParam.size() >0){

        cKey=connectionParam[0].client_id__c;

        cSecret=connectionParam[0].client_secret__c;

        }

        System.debug('Store_Cred__mdt' + connectionParam);

        string reqBody = 'grant_type=client_credentials&client_id=' + cKey + '&client_secret=' + cSecret;

        Http h = new Http();

        HttpRequest req = new HttpRequest();

        req.setBody(reqBody);

        req.setMethod('POST');

        req.setEndpoint('https://farukh-dev-ed.my.salesforce.com/services/oauth2/token');

        HttpResponse hresp = h.send(req);

        responseWrapper wResp = (responseWrapper) JSON.deserialize(hresp.getBody(), responseWrapper.class);

        system.debug('reqBody '+reqBody );

        system.debug('wResp'+wResp );

        system.debug('Instance url' + wResp.instance_url);

        system.debug('session id' + wResp.access_token);

        return wResp;

    }

    @future (callout=true)

    public static void createAccount(Set < id > accIdSet) {

        list < account > accList = new list < account > ();

        String accToken;

        String instanceUrl;

        string responseBody;

        restApiToCreateRecord obj = new restApiToCreateRecord();

        responseWrapper obj1= obj.getRequestToken();

        accToken = obj1.access_token;

        instanceUrl = obj1.instance_url;

        string endPoint = instanceURL+'/services/apexrest/createAccountRecord';

        system.debug('endPoint'+endPoint );

        system.debug('access token' + accToken);

        if (accToken != '') {

            for (Account acc: [SELECT Id,Name,Description,Type,Industry from account where id in: accIdSet]) {

            accList.add(acc);

            }

            Http h1 = new Http();

            HttpRequest req1 = new HttpRequest();

            req1.setHeader('Authorization', 'Bearer ' + accToken);

            req1.setHeader('Content-Type', 'application/json');

            req1.setMethod('POST');

            req1.setEndpoint(endPoint);

            req1.setBody(JSON.serialize(accList));

            HttpResponse hresp1 = h1.send(req1);

            system.debug('hresp1'+hresp1 );

            system.debug('hresp1.getStatusCode()'+hresp1.getStatusCode());

             system.debug('hresp1.getBody()'+hresp1.getBody());

            if (hresp1.getStatusCode() == 200) {

                system.debug('Callout Success');

            }

        }

    }

 

}

REMOTE SITE STORED IN ORG A:

The remote site url here is nothing but the instance URL of ORG B.

salesforce oauth 2.0 client credentials flow for server-to-server integration

Now, Lets try to create an account record in ORG A manually with Account Type as Prospect.

Salesforce to Salesforce integration using Client Credentials Flow

Salesforce to Salesforce integration using Client Credentials Flow

Now, Check the same record will be created in ORG B as well.

Salesforce to Salesforce integration using Client Credentials Flow

3 comments:

  1. I have an error in trigger variable does not exists:callWebserviceClass

    ReplyDelete
  2. Thanks for resource bro. But how to Integrate salesforce to SAP by using code.?

    ReplyDelete