I have a form on my WordPress website that collects additional information from customers. I want this information added to an existing record of MyCustomObject
. To do this, I will need to make a custom WordPress plugin that sends the data to Salesforce via the cURL PHP library.
How should I go about doing this without having a user logging into Salesforce? I would use Salesforce's Username-Password OAuth flow for this; however, as stated in this forum post, it is not secure and should only be used for development with Sandboxes. Is that true?
At this point, I feel as though I have no other choice but to use the Username-Password OAuth flow; I'm not a Salesforce developer so I have no idea about a good and secure way of going about this. Moreover, what I have right now only works if I send the data to a developer Sandbox. When I try to change it to send it to my Production org, I get errors like cURL 51, HTTP 500, HTTP 501
. My thought process is that if I stop using what I have now (the Force.com APEX REST API) and use Username-Password OAuth (or something else), such errors would be resolved.
As stated previously, I currently have a public APEX REST API on a Force.com site (I followed this tutorial). Below is a simplified demonstration of what I've come up with. You'll notice that it is very limited (you can't create new records or delete existing ones; you can only edit a custom field of a record).
Essentially, what the API allows me to do is pass in two parameters: someEmailAddress
and theNewFieldVal
. someEmailAddress
is used to query the records and find all of them that have the supplied email (in other words, it finds records where Email__c
is someEmailAddress
). I then loop through all of the records and set Some_Field__c
to theNewFieldVal
.
So, to recap, someEmailAddress
is merely a way to find the record(s) I would like to update, and theNewFieldVal
is the new value of Some_Field__c
.
@RestResource(urlMapping='/myendpoint/*')
global class FooBar {
@HttpPatch
global static void doPatch(String someEmailAddress, String theNewFieldVal) {
// indented so you can clearly see what's going on
List<MyCustomObject__c> results = [
SELECT Some_Field__c
FROM MyCustomObject__c
WHERE Email__c = :someEmailAddress
];
for(MyCustomObject__c o : results){
o.Some_Field__c = theNewFieldVal;
}
update results;
}
}
I use the above API with the following PATCH
cURL request in my WordPress plugin:
public function patch_salesforce($someEmailAddress, $theNewFieldVal) {
$url = 'https://<MY_COMPANY>.force.com/<MY_PATH>/services/apexrest/myendpoint';
$content = json_encode(array(
'someEmailAddress' => $someEmailAddress,
'theNewFieldVal' => $theNewFieldVal
));
$curl = curl_init($url);
curl_setopt($curl, CURLOPT_HEADER, false);
curl_setopt($curl, CURLOPT_RETURNTRANSFER, true);
curl_setopt($curl, CURLOPT_HTTPHEADER, array("Content-type: application/json"));
curl_setopt($curl, CURLOPT_CUSTOMREQUEST, "PATCH");
curl_setopt($curl, CURLOPT_POSTFIELDS, $content);
curl_exec($curl);
$status = curl_getinfo($curl, CURLINFO_HTTP_CODE);
if($status != 200) {
die("Error: call failed with status $status, curl_error " . curl_error($curl) . ", curl_errno " . curl_errno($curl));
}
curl_close($curl);
}
That all works well in development with a Sandbox, but when I changed $url
from my Sandbox's Force.com URL to my Production org's Force.com URL, I was greeted with the following error:
Error: call to URL failed with status 0, curl_error SSL: no alternative certificate subject name matches target host name '<MY_INSTANCE>.force.com', curl_errno 51
I then spent some time researching cURL error 51, and came across this post. It suggests to add the following to my cURL settings:
curl_setopt($curl, CURLOPT_SSL_VERIFYHOST, FALSE);
curl_setopt($curl, CURLOPT_SSL_VERIFYPEER, FALSE);
I tried that and got this error:
Error: call to URL failed with status 501, curl_error , curl_errno 0
If I try using only CURLOPT_SSL_VERIFYHOST
, I get the same error.
If I try using only CURLOPT_SSL_VERIFYPEER
, I get the original cURL 51 error.
Also, do I need the .secure
in $url
? Because I tried that and kept getting 500
errors.
@sfdcfox pointed out that one possible solution is to add a new certificate in Salesforce's Certificate and Key Management setup section, but which API client certificate should I use? Self-signed or one issued by a CA?
.secure
, too. Question: should Username-Password OAuth flow be only used for development with Sandboxes, or can they be used in Production?