function readOnly(count){ }
Starting November 20, the site will be set to read-only. On December 4, 2023,
forum discussions will move to the Trailblazer Community.
+ Start a Discussion
James Jones 1James Jones 1 

Server to Server REST API Access

I have a server that needs to push changes up to a Salesforce DB several times per day. There is only one Salesforce 'user' involved with this task.

How do I implement OAuth, or use an alternative scheme, to handle this scenario, and allow me to use the REST API to complete this task?  I suppose if the access token could be made to be non-expiring that could work but I am hoping for a cleaner solution.

Thanks,
James
Best Answer chosen by James Jones 1
Anupam RastogiAnupam Rastogi
Hi James,

As I understand you have two salesforce instances and wish to integrate them using OAuth. If this is correct, then follow the below steps - 

Destination Instance Configuration - 
Create a new Connected App record in this instance that will generate a set of Consumer Key and Consumer Secret. These will be required by the Source Instance for retrieving the access token.

Source Instance Configurations - 
1. Create a Remote Site Setting record in this instance mentioning the Destination instance URL.
2. Create a Trigger in the Source instance that makes a call to a class which has a method with annotation @future(callout=true)
3. Within the Trigger, check for any pre-conditions that you wish to check before triggering the interface and then call the class method.
4. Within the Class method do the following - 
     - Using the 'Salesforce User' credentials get the access token
     - Use the access token and then call the REST API resource that you wish to access like Account, Opportunity etc with the relevant input as JSON/XML.

And you are done. I am sharing a sample piece of code of the Class that should help you configure all this - 
public class SendAccountUsingRESTAPI {

    private final String clientId = '4GE…….ATL';
    private final String clientSecret = '892….465';
    private final String username = 'abc@abc.com';
    private final String password = 'testpwd5t…T9';

    public class deserializeResponse
    {
        public String id;
        public String access_token;
    }
    
    public String ReturnAccessToken (SendAccountUsingRESTAPI acount)
    {
        //--- Client Id = Consumer Key, Client Secret = Consumer Secret, Username/Password = User's Username and Password, Password should be concatenated with the Security token
        String reqbody = 'grant_type=password&client_id='+clientId+'&client_secret='+clientSecret+'&username='+username+'&password='+password;                

        Http h = new Http();
        HttpRequest req = new HttpRequest();
        req.setBody(reqbody);
        req.setMethod('POST');
        req.setEndpoint('https://login.salesforce.com/services/oauth2/token');
        HttpResponse res = h.send(req);
        
        deserializeResponse resp1 = (deserializeResponse)JSON.deserialize(res.getbody(),deserializeResponse.class);        
        return resp1.access_token;
    }
    
    @future(callout=true)
    public static void callcreateAcc (String accName, String accId)
    {
        SendAccountUsingRESTAPI acount1 = new SendAccountUsingRESTAPI();
        String accessToken;
        accessToken = acount1.ReturnAccessToken (acount1);

        if(accessToken != null){
             //--- Complete URL including the REST Resource of the Destination
             String endPoint = 'https://na23.salesforce.com/services/data/v32.0/sobjects/Account/01QU0000000DF'; 
            //--- Create the JSON String containing the fields to be sent to the destination for update      
            String jsonstr = '{"Name" : "' + accName + '"}';

            Http h1 = new Http();
            HttpRequest req1 = new HttpRequest();
            req1.setHeader('Authorization','Bearer ' + accessToken);
            req1.setHeader('Content-Type','application/json');
            req1.setHeader('accept','application/json');
            req1.setBody(jsonstr);
            req1.setMethod('POST');
            req1.setEndpoint(endPoint);
            HttpResponse res1 = h1.send(req1);      
    }
}

Thanks
AR

If you find the reply useful that solves your problem then please mark it as best answer.

All Answers

Anupam RastogiAnupam Rastogi
Hi James,

As I understand you have two salesforce instances and wish to integrate them using OAuth. If this is correct, then follow the below steps - 

Destination Instance Configuration - 
Create a new Connected App record in this instance that will generate a set of Consumer Key and Consumer Secret. These will be required by the Source Instance for retrieving the access token.

Source Instance Configurations - 
1. Create a Remote Site Setting record in this instance mentioning the Destination instance URL.
2. Create a Trigger in the Source instance that makes a call to a class which has a method with annotation @future(callout=true)
3. Within the Trigger, check for any pre-conditions that you wish to check before triggering the interface and then call the class method.
4. Within the Class method do the following - 
     - Using the 'Salesforce User' credentials get the access token
     - Use the access token and then call the REST API resource that you wish to access like Account, Opportunity etc with the relevant input as JSON/XML.

And you are done. I am sharing a sample piece of code of the Class that should help you configure all this - 
public class SendAccountUsingRESTAPI {

    private final String clientId = '4GE…….ATL';
    private final String clientSecret = '892….465';
    private final String username = 'abc@abc.com';
    private final String password = 'testpwd5t…T9';

    public class deserializeResponse
    {
        public String id;
        public String access_token;
    }
    
    public String ReturnAccessToken (SendAccountUsingRESTAPI acount)
    {
        //--- Client Id = Consumer Key, Client Secret = Consumer Secret, Username/Password = User's Username and Password, Password should be concatenated with the Security token
        String reqbody = 'grant_type=password&client_id='+clientId+'&client_secret='+clientSecret+'&username='+username+'&password='+password;                

        Http h = new Http();
        HttpRequest req = new HttpRequest();
        req.setBody(reqbody);
        req.setMethod('POST');
        req.setEndpoint('https://login.salesforce.com/services/oauth2/token');
        HttpResponse res = h.send(req);
        
        deserializeResponse resp1 = (deserializeResponse)JSON.deserialize(res.getbody(),deserializeResponse.class);        
        return resp1.access_token;
    }
    
    @future(callout=true)
    public static void callcreateAcc (String accName, String accId)
    {
        SendAccountUsingRESTAPI acount1 = new SendAccountUsingRESTAPI();
        String accessToken;
        accessToken = acount1.ReturnAccessToken (acount1);

        if(accessToken != null){
             //--- Complete URL including the REST Resource of the Destination
             String endPoint = 'https://na23.salesforce.com/services/data/v32.0/sobjects/Account/01QU0000000DF'; 
            //--- Create the JSON String containing the fields to be sent to the destination for update      
            String jsonstr = '{"Name" : "' + accName + '"}';

            Http h1 = new Http();
            HttpRequest req1 = new HttpRequest();
            req1.setHeader('Authorization','Bearer ' + accessToken);
            req1.setHeader('Content-Type','application/json');
            req1.setHeader('accept','application/json');
            req1.setBody(jsonstr);
            req1.setMethod('POST');
            req1.setEndpoint(endPoint);
            HttpResponse res1 = h1.send(req1);      
    }
}

Thanks
AR

If you find the reply useful that solves your problem then please mark it as best answer.
This was selected as the best answer
Anupam RastogiAnupam Rastogi
Hi James,

One change in the above reply. Use the following URL instead of the one given for sending the data.

Replace https://na23.salesforce.com/services/data/v32.0/sobjects/Account/01QU0000000DF
With https://na23.salesforce.com/services/data/v32.0/sobjects/Account/01QU0000000DF?_HttpMethod=PATCH

If you are not aware of the URL syntax, here is the break down - 

https://[Destination URL]/services/date/v32.0/sobjects/[Object to be updated]/[Object Id to be updated]?_HttpMethod=PATCH

Thanks
AR
James Jones 1James Jones 1
Thanks very much for this. However I am getting the error: 

Auth response: {
  "error": "invalid_grant",
  "error_description": "authentication failure"
}

Here is the code:
public static String getAccessToken ()
	{
		HttpClient httpclient = new HttpClient();

		String accessToken = "";
		String instanceUrl = "";

		PostMethod post = new PostMethod("https://test.salesforce.com/services/oauth2/token");
		post.addParameter("grant_type", "password");
		post.addParameter("client_id", clientId);
		post.addParameter("client_secret", clientSecret);
		post.addParameter("username", username);
		post.addParameter("password", password);

		try {
			httpclient.executeMethod(post);

			try {
				JSONObject authResponse = new JSONObject(
						new JSONTokener(new InputStreamReader(
								post.getResponseBodyAsStream())));
				System.out.println("Auth response: "
						+ authResponse.toString(2));

				accessToken = authResponse.getString("access_token");
				instanceUrl = authResponse.getString("instance_url");

				System.out.println("Got access token: " + accessToken);
			} catch (Exception e) {
				e.printStackTrace();
			}
		} catch (HttpException e1) {
			// TODO Auto-generated catch block
			e1.printStackTrace();
		} catch (IOException e1) {
			// TODO Auto-generated catch block
			e1.printStackTrace();
		} finally {
			post.releaseConnection();
		}	        

		return accessToken;
	}

 
Anupam RastogiAnupam Rastogi
Hi James,

I do not find any issue in your code and the grant type for this call has to be 'password' only. I hope you appended the security token in the password value.

Did you get any other lead on this issue?

Thanks
AR
James Jones 1James Jones 1
It appears that the ID I was using was not authorized to do this operation initially. It is now working with a higher level of access. Thanks!