I am trying to achieve a REST based integration between two Salesforce instances (both of them developer editions)
Expense created from source instance will be sent to the destination instance via POST.
This is my integration class in the source instance.
public class IntegrateExpenses
{
//To deserialize the response...
public class OAuth2
{
public String Id {get;set;}
public String issued_at{get;set;}
public String instance_url{get;set;}
public String signature{get;set;}
public String access_token{get;set;}
}
@future(callout=true)
public static void sendexpense(String ExpenseName,String Type,Integer Amount)
{
String clientId = '3MVG9ZL0ppGP5UrDhLqebweqGDkIkyGQRjYkfWtLLSwKDal0AhSWZIG7EU7gsYQn4JjfCt.SOoBrJLmyEpslT';
String clientSecret = '7217724494220744623';
String username = 'apiuser1982@gmail.com';
String password = 'qazwsx123UKBZb1SEA3LgCcptvGBb8ibpk';
String reqbody = 'grant_type=password&client_id='+clientId+'&clientSecret='+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);
System.debug('~~~ 1 Response Body '+res.getBody());
System.debug('~~~ 1 Response Status '+res.getStatus());
System.debug('~~~ 1 Response Status Code '+res.getStatusCode());
OAuth2 objAuthenticationInfo = (OAuth2)JSON.deserialize(res.getBody(),OAuth2.class);
//RequestWrapper rest = new RequestWrapper();
if(objAuthenticationInfo.access_token != null)
{
JSONGenerator gen = JSON.creategenerator(true);
//gen.writestartarray();
gen.writestartobject();
gen.writestringfield('ExpenseName',ExpenseName);
gen.writestringfield('Type',Type);
gen.writenumberfield('Amount',Amount);
gen.writeendobject();
//gen.writeendarray();
System.debug('~~~~ JSON Object '+gen.getAsString());
String jsonstr = gen.getAsString();
HTTP h1 = new HTTP();
HTTPRequest req1 = new HTTPRequest();
req1.setHeader('Authorization','Bearer'+objAuthenticationInfo.access_token);
req1.setHeader('Content-type','application/json');
req1.setHeader('accept','application/json');
req1.setBody(jsonstr);
req1.setMethod('POST');
req1.setEndPoint('https://login.salesforce.com/services/apexrest/Expense');
HTTPResponse res1 = h1.send(req1);
System.debug('~~~ 2 Response Body '+res.getBody());
System.debug('~~~ 2 Response Status '+res.getStatus());
System.debug('~~~ 2 Response Status Code '+res.getStatusCode());
}
}
}
I am calling the above integration class via after insert trigger (in the source instance) as below
This is the screenshots from destination instance of the connected app
This is my debug log (from the source instance)
20:22:36.038 (38490065)|CALLOUT_REQUEST|[32]|System.HttpRequest[Endpoint=https://login.salesforce.com/services/oauth2/token, Method=POST]
20:22:36.215 (215459286)|CALLOUT_RESPONSE|[32]|System.HttpResponse[Status=Bad Request, StatusCode=400]
20:22:36.215 (215509729)|SYSTEM_METHOD_EXIT|[32]|System.Http.send(ANY)
20:22:36.215 (215567868)|SYSTEM_METHOD_ENTRY|[34]|System.HttpResponse.getBody()
20:22:36.215 (215636068)|SYSTEM_METHOD_EXIT|[34]|System.HttpResponse.getBody()
20:22:36.215 (215793285)|SYSTEM_METHOD_ENTRY|[34]|System.debug(ANY)
20:22:36.215 (215806284)|USER_DEBUG|[34]|DEBUG|~~~ 1 Response Body {"error":"invalid_client","error_description":"invalid client credentials"}
Q:
From my analysis, it looks that client id (consumer key) is incorrect. But as can be seen from the code and screenshots I don't see any mismatch.
Can someone let me know as to what could be the reason behind me getting this "invalid client credentials" error message in HTTP response ?
UPDATE :
Another thing that I noticed that is do not see login attempt being done at this API user's login history.
Best Answer
For others having the same issue you could be missing the security token:
Reference: https://developer.salesforce.com/docs/atlas.en-us.api.meta/api/sforce_api_concepts_security.htm