+ Start a Discussion
LBDDLBDD 

token failed with status 0!!!

Hi,

 

I try this code:

http://developer.force.com/cookbook/recipe/interact-with-the-forcecom-rest-api-from-php

 

And when I execute, get a Salesforce.com Login, I put my login and when back to my computer (a localhost), get this error:

   https://login.salesforce.com/services/oauth2/token failed with status 0

 

Anyone can explain whats append?!!!

 

Best Regards,

LB

Best Answer chosen by Admin (Salesforce Developers) 
DohDoh

OK I used Pat's Google site test and ran the code earlier to confirm that I got the same issue. Unfortunately my temporary fix code did not work but I realized that the way I had it set up was the issue. I reran the test with the additional lines in red:

 

 

<?php

    $curl = curl_init("https://encrypted.google.com/");
	
	curl_setopt ($curl, CURLOPT_SSL_VERIFYHOST, 0);
	curl_setopt ($curl, CURLOPT_SSL_VERIFYPEER, 0);
	
    curl_setopt($curl, CURLOPT_HEADER, false);
    curl_setopt($curl, CURLOPT_RETURNTRANSFER, true);

    $json_response = curl_exec($curl);

    $status = curl_getinfo($curl, CURLINFO_HTTP_CODE);

    if ( $status != 200 ) {
        die("Error: call to token URL $token_url failed with status $status, curl_errno() "
                .curl_errno($curl).", curl_error() ".curl_error($curl).", response $json_response");
    }

    echo "Looks like everything worked ok - got status $status, response:<br/>".htmlspecialchars($json_response);

    curl_close($curl);
?>

 

 

That fixed the issue and I received Google output. So for those that have been following this blog here is what I have figured out:

 

At some recent release of the Curl library they dropped the inclusion of the CA (Certification Authority) bundle. This bundle checks that a certificate is from a root CA like Verisign, Comodo, GoDaddy etc. This only becomes an issue when running SSL and of course that is a requirement for OAuth 2.0 development.

 

A short term "work around" for developers is to add the code used above to essentially stop Curl from performing this test. However, it is not recommended as a general approach because it creates a potential security hole and not to be used in any production system. The fix to a local environment is to update the Curl library with the CA bundle and that is unique to each platform.

 

A fuller explanation of the issue and possible solutions I found on the phpbuilder.com board (http://www.phpbuilder.com/board/archive/index.php/t-10361729.html) for those interested.

 

I added both lines into the demo and I finally got some output! 

 

Bottom Line: The fix is fine for local development and testing but once the code is uploaded to a pre-production test server remember to remove the code. Better still is to add the bundle and this avoid the coding fix because it is too easy to forget to remove the lines.

 

If anyone from the Salesforce REST team is looking at this they should add something to the REST documentation about Curl setup rather than expecting developers to wade through this long explanation. And thanks Pat!!

 

Doh!

All Answers

Pat PattersonPat Patterson

Hi LB - this is pretty strange. Could you modify the code to print the response and more error diagnostics? Something like this should give us more to go on:

 

 

// In oauth_callback.php

$json_response = curl_exec($curl);

$status = curl_getinfo($curl, CURLINFO_HTTP_CODE);

if ( $status != 200 ) {
    die("Error: call to token URL $token_url failed with status $status, curl_errno() ".curl_errno($curl).", curl_error() ".curl_error($curl).", response $json_response");
}

[EDIT - added $curl parameters to curl_errno and curl_error calls]

 

Cheers,

Pat

LBDDLBDD

Hi Pat,

 

Here is the result.

 

On address webrowser:

https://localhost/sfrestapi/oauth_callback.php?code=aPrxZibfVBKPF9vKGcfyxdpjXcoie37STpwcy_xfbvMT48jrJ4N.2enDYKjb.AU%3D

 

On the webpage:

Error: call to token URL https://login.salesforce.com/services/oauth2/token failed with status 0, curl_errno() , curl_error() , response

 

Help?!

 

 

Best Regards,

LB

Pat PattersonPat Patterson

I wonder if it's a problem with the cURL installation. Put the following code in phpinfo.php on your localhost server, and see what it gives you in relation to curl.

 

 

<?php
    phpinfo();
?>

 

 

For example, my curl details (from http://ec2-72-44-49-65.compute-1.amazonaws.com/phpinfo.php ) are:

 

curl

cURL support enabled
cURL Information libcurl/7.18.2 NSS/3.12.0.3 zlib/1.2.3 libidn/0.6.14 libssh2/0.18
LBDDLBDD

Hi again Pat,

 

I have PHP v5.3.1, and this is the cURL information returned by phpinfo(), on my computer.

 

 

curl
cURL support 	        enabled
cURL Information 	7.19.6
Age 	                3
Features
AsynchDNS 	        No
Debug 	                No
GSS-Negotiate 	        No
IDN 	                Yes
IPv6 	                No
Largefile 	        Yes
NTLM 	                Yes
SPNEGO 	                No
SSL 	                Yes
SSPI 	                No
krb4 	                No
libz 	                Yes
CharConv 	        No
Protocols 	        tftp, ftp, telnet, dict, ldap, ldaps, http, file, https, ftps
Host 	                i686-pc-mingw32
SSL Version 	        OpenSSL/0.9.8l
ZLib Version 	        1.2.3 

 

 

Is realy a strange situation!!!

 

If you can illuminate me I thanks.

 

Take this opportunity to wish you a Merry Christmas.

 

Best Regards,

LB

 

 

Pat PattersonPat Patterson

Hi LB,

 

Apologies for the delay in following up - I took a few days off for the holidays.

 

One mistake in the fragment of code I posted on 12/23 - I missed the parameter from the curl_errno and curl_error calls - that die call is supposed to be

 

 

    die("Error: call to token URL $token_url failed with status $status, curl_errno() ".curl_errno($curl).", curl_error() ".curl_error($curl).", response $json_response");

 

 

That might give more detail on the problem.

 

Another thing to check would be that you can access some other website via curl - here is a quick test I just wrote to do a GET on https://encrypted.google.com - using https since the REST API endpoint is also https:

 

 

<?php
    $curl = curl_init("https://encrypted.google.com/");
    curl_setopt($curl, CURLOPT_HEADER, false);
    curl_setopt($curl, CURLOPT_RETURNTRANSFER, true);

    $json_response = curl_exec($curl);

    $status = curl_getinfo($curl, CURLINFO_HTTP_CODE);

    if ( $status != 200 ) {
        die("Error: call to token URL $token_url failed with status $status, curl_errno() "
                .curl_errno($curl).", curl_error() ".curl_error($curl).", response $json_response");
    }

    echo "Looks like everything worked ok - got status $status, response:<br/>".htmlspecialchars($json_response);

    curl_close($curl);
?>

 

Hope this helps!

 

DohDoh

Did you figure out the problem? 

 

I'm trying to get this PHP based REST demo supplied by Salesforce to work to make sure I have a baseline working environment for a PHP project  based on OAuth 2.

 

I got as far as the Salesforce "front door" and authorized the token access and got the same error.

 

Error: call to token URL https://login.salesforce.com/services/oauth2/token failed with status 0, response

 

 

I checked my PHP error log and there is nothing in there to suggest a local environment issue. For example if it was a problem with Curl wouldn't it have generated an error in the log files? I also reran with the Console.app (Mac) running and no system error is logged.

 

The URL is:

 

https://localhost/resttest/oauth_callback.php?code=aPrxZibfVBKPF9v6C26GGbh_6Hcyjkmsijpu.3hFcQYVZEPyiAOLNtlysp3eU.VElSl3W759RA%3D%3D

 

The error is generated by the callback code comes from the following PHP snippet (full listing below):

 

$status = curl_getinfo($curl, CURLINFO_HTTP_CODE);

if ( $status != 200 ) {
    die("Error: call to token URL $token_url failed with status $status, response $json_response");
}

 

I checked info.php and the Curl is enabled on version 7.20.0 so I doubt it is a curl problem. What it suggests is that the Curl token request did not find the token. 

 

 

The Salesforce full source listing for the oauth_callback.php code is:

 

 

<?php
require_once 'config.php';

session_start();

$token_url = LOGIN_URI . "/services/oauth2/token";

$code = $_GET['code'];

if (!isset($code) || $code == "") {
    die("Error - code parameter missing from request!");
}

$params = "code=" . $code
    . "&grant_type=authorization_code"
    . "&client_id=" . CLIENT_ID
    . "&client_secret=" . CLIENT_SECRET
    . "&redirect_uri=" . urlencode(REDIRECT_URI);

$curl = curl_init($token_url);
curl_setopt($curl, CURLOPT_HEADER, false);
curl_setopt($curl, CURLOPT_RETURNTRANSFER, true);
curl_setopt($curl, CURLOPT_POST, true);
curl_setopt($curl, CURLOPT_POSTFIELDS, $params);

$json_response = curl_exec($curl);

$status = curl_getinfo($curl, CURLINFO_HTTP_CODE);

if ( $status != 200 ) {
    die("Error: call to token URL $token_url failed with status $status, response $json_response");
}

curl_close($curl);

$response = json_decode($json_response, true);

$access_token = $response['access_token'];
$instance_url = $response['instance_url'];

if (!isset($access_token) || $access_token == "") {
    die("Error - access token missing from response!");
}

if (!isset($instance_url) || $instance_url == "") {
    die("Error - instance URL missing from response!");
}

$_SESSION['access_token'] = $access_token;
$_SESSION['instance_url'] = $instance_url;

header( 'Location: demo_rest.php' ) ;
?>

 

The oauth.php code is as follows:

 

 

 

<?php
require_once 'config.php';

$auth_url = LOGIN_URI
        . "/services/oauth2/authorize?response_type=code&client_id="
        . CLIENT_ID . "&redirect_uri=" . urlencode(REDIRECT_URI);

header('Location: ' . $auth_url);
?>

 

My local dev environment is:

 

OS X 10.6.6

MAMP Pro (with write all errors to logs)

PHP 5.3.2

Apache 

SSL enabled with self certificate (OpenSSL/0.9.7l)

Curl Enabled 7.20.0

Dreamweaver

Zend Framework

Salesforce DE (na7) version 20.0 (at time of writing Spring '11 not yet installed)

 

Any help would be appreciated!

 

Steve.

Pat PattersonPat Patterson

Hi Steve - do curl_errno($curl) and curl_error($curl) tell you anything useful? You can add them to the die() call:

 

die("Error: call to token URL $token_url failed with status $status, response $json_response curl_error " . curl_error($curl) . " curl_errno " . curl_errno($curl));
DohDoh

Thanks Pat,

 

Took me a while to test this out because I messed up paths and got another error .... so 3 hours later once I had figured out the problem I tested your suggestion:

 

 

Error: call to token URL https://login.salesforce.com/services/oauth2/token failed with status 0, response curl_error SSL certificate problem, verify that the CA cert is OK. Details: error:14090086:SSL routines:SSL3_GET_SERVER_CERTIFICATE:certificate verify failed curl_errno 60

 

 

 

 So it is complaining about my Self Signed Certificates using the OpenSSL framework. The certificate challenge did present as you expect:

i.e. basic steps (after I cleared the browser cache and restarted Safari):

 

1. Certificate challenge (I accepted the certificate and checked the box to always trust "localhost". )

2. Select link to run Oauth.php

3. Login to Salesforce

4. Approve requested access dialogue

5. Error running oauth_callback.php 

 

So how do you "verify that the CA cert is OK"? 

 

For the MAMP Pro SSL setup I created a folder on my desktop for the server.key, server.csr and server.crt and then moved them to folders apache/ssl_crt and apache/ssl_key respectively. 

 

Here is the link for the how to instructions for anyone interested: http://www.rockettheme.com/blog/coding/310-getting-ssl-to-work-with-mamp-pro

 

Is it possible that the site is not finding the certificates? below is the Apache ssl.conf

 

<VirtualHost resttestphp:443>
DocumentRoot "/Applications/MAMP/htdocs_ssl"
ServerName resttestphp
SSLEngine on
SSLCertificateFile /Applications/MAMP/conf/apache/ssl_crt/server.crt
SSLCertificateKeyFile /Applications/MAMP/conf/apache/ssl_key/server.key
<Directory "/Applications/MAMP/htdocs_ssl">
Options All
AllowOverride All
Order allow,deny
Allow from all
</Directory>
</VirtualHost>
#</IfDefine>

 

 

 Steve

 

 

 

Pat PattersonPat Patterson

Hi Steve - I don't think it's your self-signed cert that's the problem - at this point of the protocol, PHP/cURL is doing a POST to Salesforce. It looks like, for some reason, PHP doesn't trust the Salesforce cert, which is odd, since I just checked, and it's issued by Verisign under their 1996 vintage CA root cert, so it shouldn't pose a problem.

 

One diagnostic I suggested earlier in this thread is to try a GET on Google and see what happens. If that also fails, you need to look at your trusted CA list. I haven't had to mess with this, but this blog post talks about it.

DohDoh

Pat

 

I think I have narrowed down the issue:

 

According to a Joomla forum post the issue is due to the Curl library"

 

" This is due to CURL lib on many systems (windows, WAMP, and MAMP installs included) not having trust certificates for the major certificate authorities. Instead of importing PEMs for each major CA, to fix just disable the CURL verify peer settings. It makes CURL skip checking the certificate against known CAs (which aren't installed to begin with).
This is due to CURL lib on many systems (windows, WAMP, and MAMP installs included) not having trust certificates for the major certificate authorities. Instead of importing PEMs for each major CA,  disable the CURL verify peer settings. It makes CURL skip checking the certificate against known CAs (which aren't installed to begin with)."

 

 

curl_setopt($fp, CURLOPT_SSL_VERIFYPEER, false);

 I'm not familiar (yet) with curl so it is not clear to me if this is code required in every php file that uses curl (i.e. require_once()) or if the library itself must be changed with the overhead that every time it is upgraded you have to remember to apply the fix. 

 

Any thoughts on best practice? 

 

DohDoh

Also is this a change required on the Salesforce server? or can it be handled locally? 

Pat PattersonPat Patterson

Best practice would be to configure your trusted root certificate list to include the Verisign root cert that Salesforce uses. A quick workaround (some would call it a hack) would be to use curl_setopt($fp, CURLOPT_SSL_VERIFYPEER, false) to disable certificate checking. The downside of this is that you would accept any old certificate that was presented, so you would be vulnerable to a man-in-the-middle attack.

 

As far as I know, you would require that curl_setopt() call after every curl_init() on an https URL, since it sets the option for just that connection.

DohDoh

I took a look at the certificates in my Key Chain and discovered that the Force.com certiicate had expired in 9/11/2009 but it was set to be always trusted so I guess during normal working use its not a problem.

 

As you say I don't care for the hack. As I understand it I can go online and generate either a Salesforce signed or a CA-signed certificate. That would be emailed to me and I can accept it to add into my keychain. The question is can I get away with the Salesforce signed version? To be safe I will go for the CA-signed one.

DohDoh

I first set up a Salesforce Self Signed certificate, downloaded and added to my key chain. I also added a copy of the certificate in the apache/ssl_crt folder. Unfortunately I still get the following error after the login page:

 

 

Error: call to token URL https://login.salesforce.com/services/oauth2/token failed with status 0, response curl_error SSL certificate problem, verify that the CA cert is OK. Details: error:14090086:SSL routines:SSL3_GET_SERVER_CERTIFICATE:certificate verify failed curl_errno 60

 It seems (as suspected) that the certificate must be signed by a listed CA for the Curl Library to accept it. I will try a CA version.

 

I also tried a coding option to see if that would work but it did not:

 

 

Added:

require_once 'curlfix.php';

For source:

<?php

	$curl = curl_init();
	curl_setopt($curl, CURLOPT_SSL_VERIFYPEER, 0);
?>

 

 

 

DohDoh

OK I used Pat's Google site test and ran the code earlier to confirm that I got the same issue. Unfortunately my temporary fix code did not work but I realized that the way I had it set up was the issue. I reran the test with the additional lines in red:

 

 

<?php

    $curl = curl_init("https://encrypted.google.com/");
	
	curl_setopt ($curl, CURLOPT_SSL_VERIFYHOST, 0);
	curl_setopt ($curl, CURLOPT_SSL_VERIFYPEER, 0);
	
    curl_setopt($curl, CURLOPT_HEADER, false);
    curl_setopt($curl, CURLOPT_RETURNTRANSFER, true);

    $json_response = curl_exec($curl);

    $status = curl_getinfo($curl, CURLINFO_HTTP_CODE);

    if ( $status != 200 ) {
        die("Error: call to token URL $token_url failed with status $status, curl_errno() "
                .curl_errno($curl).", curl_error() ".curl_error($curl).", response $json_response");
    }

    echo "Looks like everything worked ok - got status $status, response:<br/>".htmlspecialchars($json_response);

    curl_close($curl);
?>

 

 

That fixed the issue and I received Google output. So for those that have been following this blog here is what I have figured out:

 

At some recent release of the Curl library they dropped the inclusion of the CA (Certification Authority) bundle. This bundle checks that a certificate is from a root CA like Verisign, Comodo, GoDaddy etc. This only becomes an issue when running SSL and of course that is a requirement for OAuth 2.0 development.

 

A short term "work around" for developers is to add the code used above to essentially stop Curl from performing this test. However, it is not recommended as a general approach because it creates a potential security hole and not to be used in any production system. The fix to a local environment is to update the Curl library with the CA bundle and that is unique to each platform.

 

A fuller explanation of the issue and possible solutions I found on the phpbuilder.com board (http://www.phpbuilder.com/board/archive/index.php/t-10361729.html) for those interested.

 

I added both lines into the demo and I finally got some output! 

 

Bottom Line: The fix is fine for local development and testing but once the code is uploaded to a pre-production test server remember to remove the code. Better still is to add the bundle and this avoid the coding fix because it is too easy to forget to remove the lines.

 

If anyone from the Salesforce REST team is looking at this they should add something to the REST documentation about Curl setup rather than expecting developers to wade through this long explanation. And thanks Pat!!

 

Doh!

This was selected as the best answer
Pat PattersonPat Patterson

Good to see you got it working. I'll read the explanation you linked to and update the cookbook recipe as soon as I can. Thanks for taking the time to document resolution of the issue!

LBDDLBDD

Hello,

 

Thanks a lot to Pat and Doh, this workaround really works! :)

 

 

 

In oauth_callback.php:


(....)
$params = "code=" . $code
    . "&grant_type=authorization_code"
    . "&client_id=" . CLIENT_ID
    . "&client_secret=" . CLIENT_SECRET
    . "&redirect_uri=" . urlencode(REDIRECT_URI);

$curl = curl_init($token_url);

	curl_setopt ($curl, CURLOPT_SSL_VERIFYHOST, 0);
	curl_setopt ($curl, CURLOPT_SSL_VERIFYPEER, 0);
	
curl_setopt($curl, CURLOPT_HEADER, false);
curl_setopt($curl, CURLOPT_RETURNTRANSFER, true);
curl_setopt($curl, CURLOPT_POST, true);
curl_setopt($curl, CURLOPT_POSTFIELDS, $params);

$json_response = curl_exec($curl);

(....)

 

You need to put in all cURL call, after  "$curl = curl_init....", in demo_rest.php

 

 

 

Best Regards,

LB

 

 

saurabhEventsaurabhEvent

I get following error when i try to reterive the Account Records:

 

Error: call to URL https://na9.salesforce.com/services/data/v20.0/sobjects/Account/ failed with status 0, response , curl_error SSL certificate problem, verify that the CA cert is OK. Details: error:14090086:SSL routines:SSL3_GET_SERVER_CERTIFICATE:certificate verify failed, curl_errno 60

 

Any help on this.

 

Thanks

 

 

Pat PattersonPat Patterson

Hi saurabhEvent - did you try the solutions posted earlier in this thread?

saurabhEventsaurabhEvent

Thanks Pat for looking into this, yes i have applied changes suggested in earlier post.

 

curl_setopt($curl, CURLOPT_HEADER, false);

curl_setopt($curl, CURLOPT_RETURNTRANSFER, true);

curl_setopt($curl, CURLOPT_POST, true);

curl_setopt($curl, CURLOPT_SSL_VERIFYHOST, 0);

curl_setopt($curl, CURLOPT_SSL_VERIFYPEER, 0);

curl_setopt($curl, CURLOPT_POSTFIELDS, $params);

 

I was able to overcome first error which i got, but while displaying records i get following error, I am new to Oath in Salesforce and have been following steps at http://developer.force.com/cookbook/recipe/interact-with-the-forcecom-rest-api-from-php

 

Thanks

saurabhEventsaurabhEvent

I think i figured it out, i had one more instance of $curl declared, once i setted same parameter for my query it worked fine.

 

Thanks

CarrieTechCarrieTech

I just wanted to say THANK YOU for this post.  I ran into the same issue and was able to resolve it by following the directions here.  For those reading this post and still having trouble with the certificates, there are five instances of "curl_init" in the demo_rest.php file and one in the oauth_callback.php.  If you add these two lines of code under each instance, you can bypass the error message for testing.  As mentioned, you should NOT do this in a production environment.

 

Add these lines of code:
curl_setopt ($curl, CURLOPT_SSL_VERIFYHOST, 0);
curl_setopt ($curl, CURLOPT_SSL_VERIFYPEER, 0);

 

This is for those trying to test the code sample from "Interact with the Force.com REST API from PHP"

http://developer.force.com/cookbook/recipe/interact-with-the-forcecom-rest-api-from-php

vlrvlr

Hey,

Thank you for detailed explanations. I am also going through this example, and I was getting the same errors. I tried to implement more permanent solution with  

 

curl_setopt($curl, CURLOPT_CAINFO, 'C:\dev\curl\cacert.pem');

 

from here http://kb.ucla.edu/articles/how-do-i-use-curl-in-php-on-windows .

 

I downloaded cacert.pem from this link http://curl.haxx.se/docs/caextract.html .

 

It works for the example with google ("https://encrypted.google.com/";) , but does not work with salesforce. I am getting the following error:

 

Error: call to token URL https://test.salesforce.com/services/oauth2/token failed with status 400, curl_errno() 0, curl_error() , response {"error":"unsupported_grant_type","error_description":"grant type not supported"}

 

Any ideas please?

Pat PattersonPat Patterson
It's been a while, but for the sake of completeness... vlr - if you're getting back HTTP error 400, then TLS is working just fine, and you have a problem in the parameters you're sending to https://test.salesforce.com/services/oauth2/token 
Yevhenii ShkodaYevhenii Shkoda
Error: call to token URL https://na55.salesforce.com/services/oauth2/token failed with status 0, response , curl_error , curl_errno 0
George GarchagudashviliGeorge Garchagudashvili
I only fixed the problem from this: https://stackoverflow.com/questions/24611640/curl-60-ssl-certificate-unable-to-get-local-issuer-certificate
Vivek Sangani 2Vivek Sangani 2
How can we upload pdf in lead using curl ? Is there any other way to upload document in lead as an attachment?