I've been trying to create a Paypal adaptive payments API call to the sandbox all day now without success. I've read dozends of tutorials, SE threads etc but nothing I tried worked. I keep getting the "Authentication failed. API credentials are incorrect." error message.
The following is the code I'm using:
$baseurl = 'https://svcs.sandbox.paypal.com/AdaptivePayments/Pay';
define('PAYPAL_API_USER', '<snip>');
define('PAYPAL_API_PWD', '<snip>');
define('PAYPAL_API_SIGNATURE', '<snip>');
define('PAYPAL_API_APPLICATION_ID', 'APP-80W284485P519543T');
$returnurl = "<snip>";
$cancelurl = "<snip>";
$data = array(
"actionType" => "PAY",
"currencyCode" => "USD",
"receiverList" => array(
"receiver" => array(
array(
"amount" => "1.00",
"email" => "<snip>"
),
)
),
"returnUrl" => $returnurl,
"cancelUrl" => $cancelurl,
"requestEnvelope" => array(
"errorLangauge" => "en_US",
"detailLevel" => "ReturnAll",
)
);
$headers = array(
"X-PAYPAL-SECURITY-USERID: ".PAYPAL_API_USER,
"X-PAYPAL-SECURITY-PASSWORD: ".PAYPAL_API_PWD,
"X-PAYPAL-SECURITY-SIGNATURE: ".PAYPAL_API_SIGNATURE,
"X-PAYPAL-SECURITY-REQUEST-DATA-FORMAT: JSON",
"X-PAYPAL-SECURITY-RESPONSE-DATA-FORMAT: JSON",
"X-PAYPAL-SECURITY-APPLICATION-ID: ".PAYPAL_API_APPLICATION_ID,
);
$ch = curl_init();
curl_setopt ($ch, CURLOPT_URL, $baseurl);
curl_setopt ($ch, CURLOPT_RETURNTRANSFER, TRUE);
curl_setopt ($ch, CURLOPT_SSL_VERIFYPEER, FALSE);
curl_setopt ($ch, CURLOPT_SSL_VERIFYHOST, FALSE);
curl_setopt ($ch, CURLOPT_POSTFIELDS, json_encode($data));
curl_setopt ($ch, CURLOPT_HEADER, $headers);
print_r(curl_exec($ch));
I created several test accounts under "Sandbox Test Accounts" on developer.paypal.com. I tried using their username + password + signature (from the API Credentials tab) in the code above.
Always getting "Authentication failed. API credentials are incorrect."
Edit 1:
On this page: https://developer.paypal.com/docs/classic/adaptive-payments/gs_AdaptivePayments/ they have a similar curl command. I run this command:
curl -s --insecure -H "X-PAYPAL-SECURITY-USERID: caller_1312486258_biz_api1.gmail.com" -H "X-PAYPAL-SECURITY-PASSWORD: 1312486294" -H "X-PAYPAL-SECURITY-SIGNATURE: AbtI7HV1xB428VygBUcIhARzxch4AL65.T18CTeylixNNxDZUu0iO87e" -H "X-PAYPAL-REQUEST-DATA-FORMAT: JSON" -H "X-PAYPAL-RESPONSE-DATA-FORMAT: JSON" -H "X-PAYPAL-APPLICATION-ID: APP-80W284485P519543T" https://svcs.sandbox.paypal.com/AdaptivePayments/Pay -d "{\"actionType\":\"PAY\", \"currencyCode\":\"USD\", \"receiverList\":{\"receiver\":[{\"amount\":\"1.00\",\"email\":\"rec1_1312486368_biz#gmail.com\"}]}, \"returnUrl\":\"http://www.example.com/success.html\", \"cancelUrl\":\"http://www.example.com/failure.html\", \"requestEnvelope\":{\"errorLanguage\":\"en_US\", \"detailLevel\":\"ReturnAll\"}}"
in a terminal window and got a payment created success response.
So next I switched the userid/password/signature in this command with the ones from the original question, and guess what, that worked too!
Finally I used the userid/password/signature from the example in the PHP curl code from my original question and again got the "Authentication failed. API credentials are incorrect." message.
To sum things up both userid/password/signature combinations (mine and Paypal's) generate a success response if run via terminal, but both produce authentication failure errors when run via my PHP CURL code. So there is definitely something wrong in my original code, question is WHAT??
Edit 2:
Still can't get it to work, but I'm thinking it's something to do with the headers bit. Here is why: take a look at the full response I'm getting:
HTTP/1.1 200 OK
Date: Tue, 13 Oct 2015 11:51:23 GMT
Server: Apache
X-EBAY-SOA-REQUEST-ID: 150610a6-a690-a488-6781-12e6ffa2f8dd!AdaptivePayments!10.72.134.120![]
X-PAYPAL-SERVICE-VERSION: 1.0.0
X-PAYPAL-SERVICE-NAME: {http://svcs.paypal.com/types/ap}AdaptivePayments
X-EBAY-SOA-RESPONSE-DATA-FORMAT: XML
X-PAYPAL-OPERATION-NAME: Pay
CACHE-CONTROL: no-cache
X-PAYPAL-ERROR-RESPONSE: TRUE
X-EBAY-SOA-MESSAGE-PROTOCOL: NONE
Set-Cookie: Apache=10.72.108.11.1444737084008373; path=/; expires=Thu, 05-Oct-45 11:51:24 GMT
Vary: Accept-Encoding
Paypal-Debug-Id: 32922591f3d33
Set-Cookie: X-PP-SILOVER=name%3DSANDBOX3.APIT.1%26silo_version%3D880%26app%3Dadaptivepaymentspartaweb_api3t%26TIME%3D1005591638; domain=.paypal.com; path=/; Secure; HttpOnly
Set-Cookie: X-PP-SILOVER=; Expires=Thu, 01 Jan 1970 00:00:01 GMT
Connection: close
Transfer-Encoding: chunked
Content-Type: text/xml;charset=UTF-8
<?xml version='1.0' encoding='UTF-8'?><ns3:FaultMessage xmlns:ns3="http://svcs.paypal.com/types/common" xmlns:ns2="http://svcs.paypal.com/types/ap"><responseEnvelope><timestamp>2015-10-13T04:51:24.021-07:00</timestamp><ack>Failure</ack><correlationId>e133487976d4b</correlationId><build>17820627</build></responseEnvelope><error><errorId>520003</errorId><domain>PLATFORM</domain><subdomain>Application</subdomain><severity>Error</severity><category>Application</category><message>Authentication failed. API credentials are incorrect.</message></error></ns3:FaultMessage>
It's XML why I specified JSON as the response data format. So if the response format line is ignored or not properly read I guess the same thing is messing the login details. Hope this is a good clue...
If you are 100% certain that the API Credentials for a business Sandbox account are correct then verify you have the correct App id. The APP Id needs to be the APP id from the application you submitted for Adaptive Payments.
If you have not submitted an application yet here are the instructions:
How to Submit a Developer Application
If you have already applied for Adaptive Payments go to your list of applications, and click on your application to verify the correct App id.
Related
I am attempting to use the Rest API in Magento 2. I have a piece of PHP that uses cURL to first get an admin token for my Magento user, then use the token to return a piece of Magento data (in this example a list of product types). The first part returns a token with no problems, but the second part comes back with an HTTP 401 Basic Authentication error.
My code is:
<?php
// Get handle for token retrieval
$userData = array("username" => "user", "password" => "password!");
$ch = curl_init("https://my.magento/rest/V1/integration/admin/token/");
// Set options
curl_setopt($ch, CURLOPT_CUSTOMREQUEST, "POST");
curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode($userData));
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_HTTPHEADER, array("Content-Type: application/json", "Content-Length: " . strlen(json_encode($userData))));
curl_setopt($ch, CURLOPT_VERBOSE, true);
$verbose = fopen('/tmp/curl.log', 'w+');
curl_setopt($ch, CURLOPT_STDERR, $verbose);
// Get token
$token = curl_exec($ch);
echo "Token returned: " . $token . "<BR><BR>";
// Display log
rewind($verbose);
$verboseLog = stream_get_contents($verbose);
echo "Verbose information 1:\n<pre>", htmlspecialchars($verboseLog), "</pre>\n";
echo "About to get product<BR>";
// Get handle for product types
$ch = curl_init("https://my.magento/rest/V1/products/types/");
// Set options
curl_setopt($ch, CURLOPT_CUSTOMREQUEST, "GET");
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_HTTPHEADER, array("Content-Type: application/json", "Authorization: Bearer " . json_decode($token)));
curl_setopt($ch, CURLOPT_VERBOSE, true);
$verbose = fopen('/tmp/curl.log', 'w+');
curl_setopt($ch, CURLOPT_STDERR, $verbose);
// Get types
$result = curl_exec($ch);
echo "Result: " . $result . "<BR>";
// Display log
rewind($verbose);
$verboseLog = stream_get_contents($verbose);
echo "<BR>Verbose information 2:\n<pre>", htmlspecialchars($verboseLog), "</pre>\n";
?>
And the browser output is:
Tokenreturned: "t8iskt68xlo5frf9hhtc1lk8wmqzbzx8"
Verbose information 1:
* About to connect() to my.magento port 443 (#2)
* Trying 104.25.128.20...
* Connected to mymagento (nn.nn.nn.nn) port 443 (#2)
* CAfile: /etc/pki/tls/certs/ca-bundle.crt
CApath: none
* SSL connection using TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256
* Server certificate:
* subject: CN=ssl379212.cloudflaressl.com,OU=PositiveSSL Multi-Domain,OU=Domain Control Validated
* start date: Oct 26 00:00:00 2018 GMT
* expire date: May 04 23:59:59 2019 GMT
* common name: ssl379212.cloudflaressl.com
* issuer: CN=COMODO ECC Domain Validation Secure Server CA 2,O=COMODO CA Limited,L=Salford,ST=Greater Manchester,C=GB
> POST /rest/V1/integration/admin/token/ HTTP/1.1
Host: sand2.firetoys.co.uk
Accept: */*
Content-Type: application/json
Content-Length: 48
* upload completely sent off: 48 out of 48 bytes
< HTTP/1.1 200 OK
< Date: Wed, 31 Oct 2018 12:50:01 GMT
< Content-Type: application/json; charset=utf-8
< Content-Length: 34
< Connection: keep-alive
< Set-Cookie: __cfduid=d69af7d1f0a1205231a8867c1f45875621540990201; expires=Thu, 31-Oct-19 12:50:01 GMT; path=/; domain=.my.magento; HttpOnly
< X-Frame-Options: SAMEORIGIN
< X-UA-Compatible: IE=edge
< Pragma: no-cache
< Expires: -1
< Cache-Control: no-store, no-cache, must-revalidate, max-age=0
< Accept-Ranges: bytes
< Set-Cookie: PHPSESSID=9p378rsfito8gfocnrufucssh6; expires=Wed, 31-Oct-2018 13:50:01 GMT; Max-Age=3600; path=/; domain=sand2.firetoys.co.uk; secure; HttpOnly
< Expect-CT: max-age=604800, report-uri="https://report-uri.cloudflare.com/cdn-cgi/beacon/expect-ct"
< Server: cloudflare
< CF-RAY: 47263eb629ea0ce9-LHR
<
* Connection #2 to host my.magento left intact
About to get product
Result:
Verbose information 2:
* About to connect() to my.magento port 443 (#3)
* Trying nn.nn.nn.nn...
* Connected to my.magento (nn.nn.nn.nn) port 443 (#3)
* CAfile: /etc/pki/tls/certs/ca-bundle.crt
CApath: none
* SSL connection using TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256
* Server certificate:
* subject: CN=ssl379212.cloudflaressl.com,OU=PositiveSSL Multi-Domain,OU=Domain Control Validated
* start date: Oct 26 00:00:00 2018 GMT
* expire date: May 04 23:59:59 2019 GMT
* common name: ssl379212.cloudflaressl.com
* issuer: CN=COMODO ECC Domain Validation Secure Server CA 2,O=COMODO CA Limited,L=Salford,ST=Greater Manchester,C=GB
> GET /rest/V1/products/types/ HTTP/1.1
Host: sand2.firetoys.co.uk
Accept: */*
Content-Type: application/json
Authorization: Bearer t8iskt68xlo5frf9hhtc1lk8wmqzbzx8
< HTTP/1.1 401 Unauthorized
< Date: Wed, 31 Oct 2018 12:50:01 GMT
< Content-Length: 0
< Connection: keep-alive
< Set-Cookie: __cfduid=d38c9e4bc3019d9ac55c7f68f5c5ca1161540990201; expires=Thu, 31-Oct-19 12:50:01 GMT; path=/; domain=.my.magento; HttpOnly
< X-Varnish: 7995397
< WWW-Authenticate: Basic
< Expect-CT: max-age=604800, report-uri="https://report-uri.cloudflare.com/cdn-cgi/beacon/expect-ct"
< Server: cloudflare
< CF-RAY: 47263eb70f5b3512-LHR
<
* Connection #3 to host my.magento left intact
When I try just browsing directly to https://my.magento/rest/V1/products/types/ I get a Magento error back saying I am not authorised for the Products resource, which I would expect as I am sending no token or login credentials, but at least it is getting through to Magento.
Any ideas??
I should add that the server is set for Basic authentication, and if I replace the Bearer auth with the necessary Basic auth in the header for the GET, it returns the Magento message about not having access to the resource, which is fair enough. So I guess there are two questions:
How can I get past the basic authentication and still include the bearer authentication in my GET request, given that you can't put two authentications into the header?
Why does the initial POST to get the token work without any basic auth??
"How can I get past the basic authentication and still include the bearer authentication in my GET request, given that you can't put two authentications into the header?"
Disable auth for /index.php/rest location (in webserver)
"Why does the initial POST to get the token work without any basic auth??"
If the POST location is protected then you should get a 401 response.
Did you put the username and password on url on post request? http://user:pass#my.magento/rest/V1/
By the way, putting user:pass#my.magento into URL, will be translated into Authorization: User .
But you also set Authorization: Bearer t8iskt68xlo5frf9hhtc1lk8wmqzbzx8 which will overwrite the http authentification Authorization.
I'm running into a problem with a 302 redirect after my CORS preflight has successfully returned a 200 status. I'm currently building an app using Laravel 4.1 and Angular 1.2 as well as my own OAUTH2 server.
The error that Chrome/FF/Safari are sending back to me is:
XMLHttpRequest cannot load http://localhost.api/api/v1/tracks?$filter=id%20eq%20guid%27d7de10ba-e353-455b-a3cb-ced9b4965141%27&. The request was redirected to 'http://localhost.api/session/invalid', which is disallowed for cross-origin requests that require preflight.
I assume whats causing my issue is the "redirect" thats happening - as my normal CORS requests all work as expected.
My configuration for my Access-Control-Allow-* headers is fairly open right now during testing.
'paths' => array(
'^/api/' => array(
'allow_origin'=> array('*'),
'allow_headers'=> array('Content-Type', 'Authorization'),
'allow_methods'=> array('POST', 'PUT', 'GET', 'DELETE', 'OPTIONS'),
'max_age' => 0
),
'^/session/' => array(
'allow_origin'=> array('*'),
'allow_headers'=> array('Content-Type', 'Authorization'),
'allow_methods'=> array('GET', 'OPTIONS'),
'max_age' => 0
)
The redirect in question is in a pre-filter thats checking the validity of an OAUTH2 access token
public function filter($route, $request, $data = null)
{
// Get the authorization header or fail
if ($authorization = Request::header('Authorization', false)) {
list($type, $token) = explode(' ', $authorization);
if (is_null($auth = OAuth2::token($token)->first())) {
return Redirect::to('session/invalid');
}
$tokenExpiryDate = Carbon::createFromTimeStamp($auth->access_token_expires);
// If we don't have a Bearer authentication header
// or if the token has expired. Then redirect to an
// expired session route
if ( 'bearer' != strtolower($type)
|| Carbon::now()->gt($tokenExpiryDate)
) {
return Redirect::route(
'expiredSession',
array('expiry' => $tokenExpiryDate->timestamp)
);
}
} else {
// The authentication header is invalid, redirect to let the user know.
return Redirect::to('session/invalid');
}
}
All these requests worked when I tried debugging using POSTMAN, but after my research I've basically found that extensions don't necessarily have to play by the same rules. As well as I noticed my requests using POSTMAN never send any preflight OPTIONS requests when I initiate a simple GET, POST, etc..
Here are the headers of both an OPTIONS request as well as a GET request to follow it that is returning my error
OPTIONS Request
Remote Address:127.0.0.1:80
Request URL:http://localhost.api/api/v1/tracks?$filter=id%20eq%20guid%27d7de10ba-e353-455b-a3cb-ced9b4965141%27&
Request Method:OPTIONS
Status Code:200 OK
Request Headers
Accept:*/*
Accept-Encoding:gzip,deflate,sdch
Accept-Language:en-US,en;q=0.8
Access-Control-Request-Headers:accept, authorization
Access-Control-Request-Method:GET
Cache-Control:no-cache
Connection:keep-alive
DNT:1
Host:vegas.ine.com
Origin:http://localhost.angular
Pragma:no-cache
Referer:http://localhost.angular/admin/
User-Agent:Mozilla/5.0 (Macintosh; Intel Mac OS X 10_9_2) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/34.0.1847.131 Safari/537.36
Response Headers
Access-Control-Allow-Headers:content-type, authorization
Access-Control-Allow-Methods:POST, PUT, GET, DELETE, OPTIONS
Access-Control-Allow-Origin:http://localhost.angular
Cache-Control:no-cache
Connection:close
Content-Type:text/html
Date:Thu, 01 May 2014 16:22:19 GMT
Server:Apache/2.2.26 (Unix) DAV/2 PHP/5.4.24 mod_ssl/2.2.26 OpenSSL/0.9.8y
Set-Cookie:laravel_session=eyJpdiI6IktOZjlTM1ZVNUx0TEhoaTczY3dQcDBKRWlvbnppbDA3QTdqSENJdTc2R1U9IiwidmFsdWUiOiJEZ2ltXC9mNm1Qa20rV3BVRlNHTXgySGtUeVlpNjNZcGFudDFBWDJJekl1MEVNVlhSRE5WWk5YZDNxUkZuU0VEVytcL3NLNlVBXC9hZWtJQzdHU2FqVWtMdz09IiwibWFjIjoiYTYxYjEwNjlmYmI2MjMwNmE4MzlkYjIwNGZlNzA4Y2ViZGVkZmU1MTQzMzc5NmU2YzI2ZGExNzYxY2U5ZjdiMCJ9; expires=Thu, 01-May-2014 18:22:19 GMT; path=/; httponly
X-Frame-Options:SAMEORIGIN
X-Powered-By:PHP/5.4.24
GET Request
Remote Address:127.0.0.1:80
Request URL:http://localhost.api/api/v1/tracks?$filter=id%20eq%20guid%27d7de10ba-e353-455b-a3cb-ced9b4965141%27&
Request Method:GET
Status Code:302 Found
Request Headers
Accept:application/json, text/plain, */*
Accept-Encoding:gzip,deflate,sdch
Accept-Language:en-US,en;q=0.8
Authorization:Bearer 6Ss4XPrPM5jQD7Es0dz7TPRQ76hGA69vT9K94pst
Cache-Control:no-cache
Connection:keep-alive
DNT:1
Host:vegas.ine.com
Origin:http://localhost.angular
Pragma:no-cache
Referer:http://localhost.angular/admin/
User-Agent:Mozilla/5.0 (Macintosh; Intel Mac OS X 10_9_2) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/34.0.1847.131 Safari/537.36
Response Headers
Access-Control-Allow-Origin:http://localhost.angular
Cache-Control:no-cache
Connection:Keep-Alive
Content-Type:text/html; charset=UTF-8
Date:Thu, 01 May 2014 16:22:19 GMT
Keep-Alive:timeout=5, max=100
Location:http://localhost.api/session/invalid
Server:Apache/2.2.26 (Unix) DAV/2 PHP/5.4.24 mod_ssl/2.2.26 OpenSSL/0.9.8y
Set-Cookie:laravel_session=eyJpdiI6InlnREVPcUJTcyswMnRLanFDSlZ6QWFBVXZWMGdMNVNLYWxNTHRJVUlkalk9IiwidmFsdWUiOiJ4aXN5U0dcL1NYeGQrcUVzWFhYV3o2MWhcL25hQTlhcVUxbWxkN2R6SG9KZDNKaGNLTkRQY2FyTitpVHNGZzYxVVRtZUhoZGZRWE9GWjZRaDd1VVwvZUZuUT09IiwibWFjIjoiY2EzZTViZGIzZmVlMDcwZjdhMzBjOWQxYTgwZWNlYTJiMDk3ODdlZTk3NTYxMDNmM2YyODJjOGIxMzBmMmJlMiJ9; expires=Thu, 01-May-2014 18:22:20 GMT; path=/; httponly
Transfer-Encoding:chunked
Vary:Authorization
X-Clockwork-Id:1398961340.2239.1349476325
X-Clockwork-Version:1.5
X-Frame-Options:SAMEORIGIN
X-Powered-By:PHP/5.4.24
I have done something like this and it worked fine for me
//pattern to allow origins
$allowedOriginPattern = /** YOUR PATTERNS **/;
$allowedOrigin = "";
if (preg_match($allowedOriginPattern, $_SERVER['HTTP_ORIGIN'])) {
$allowedOrigin = $_SERVER['HTTP_ORIGIN'];
}
/**
* set http content type
*/
header('Content-Type: application/json;charset=UTF-8');
header('Access-Control-Allow-Origin: ' . $allowedOrigin);
header('Access-Control-Allow-Methods: DELETE, HEAD, GET, OPTIONS, POST, PUT');
header('Access-Control-Allow-Headers: Content-Type, Content-Range, Content-Disposition, Content-Description');
header('Access-Control-Max-Age: 1728000');
I have added this code in laravel index.php
Here is the reference for CORS
http://www.w3.org/TR/cors/#cross-origin-request-with-preflight-0
Spent an hour and this trying to redirect to a subdomain
Instead just used javascript after a successful response
window.location.href = resp.data.redirect
i'm trying to use an refresh token from the oAuth2 web redirect auth in my console perl script. The client id is the same and correct client id i used in my javascript an i checked it 5 times that it ist the same as i have in my google API's Console.
The client secret is checked two and it is correct.
The refresh token was created with approval_prompt=force&access_type=offline
Here is my perl sample code i use:
# -----------------------------------------------------------------------------------
my $CLIENT_ID = 'XXXXX.apps.googleusercontent.com';
my $CLIENT_SECRET = 'YYYYYYYYYYY';
# -----------------------------------------------------------------------------------
# TESTING
my $refresh_token = '1/is_5_minutes_old';
# -----------------------------------------------------------------------------------
my $string = '';
$string .= 'grant_type=refresh_token';
$string .= '&client_id=' . $CLIENT_ID;
$string .= '&client_secret=' . $CLIENT_SECRET;
$string .= '&refresh_token=' . $refresh_token;
$ua = LWP::UserAgent->new;
my $req =
HTTP::Request->new( POST => 'https://accounts.google.com/o/oauth2/token' );
$req->content_type('application/x-www-form-urlencoded');
$req->content($string);
print $string . "\n";
my $res = $ua->request($req);
print $res->as_string;
The response of it:
HTTP/1.1 400 Bad Request
Cache-Control: no-cache, no-store, max-age=0, must-revalidate
Connection: close
Date: Mon, 02 Sep 2013 10:50:26 GMT
Pragma: no-cache
Server: GSE
Content-Type: application/json
Expires: Fri, 01 Jan 1990 00:00:00 GMT
Alternate-Protocol: 443:quic
Client-Date: Mon, 02 Sep 2013 10:50:26 GMT
Client-Peer: 74.125.136.84:443
Client-Response-Num: 1
Client-SSL-Cert-Issuer: /C=US/O=Google Inc/CN=Google Internet Authority G2
Client-SSL-Cert-Subject: /C=US/ST=California/L=Mountain View/O=Google Inc/CN=accounts.google.com
Client-SSL-Cipher: RC4-SHA
Client-SSL-Warning: Peer certificate not verified
X-Content-Type-Options: nosniff
X-Frame-Options: SAMEORIGIN
X-XSS-Protection: 1; mode=block
{
"error" : "unauthorized_client"
}
i hope you have an idea to help.
greatings
Invalid client usually means that the client ID and client secret don't match, or there is a typo in one of them (though you mention you've double checked this!). Nothing in your code looks wrong.
When you retrieve the refresh token, could you try putting the access token that comes along with it into the tokeinfo endpoint and making sure the values for client ID there match the ones you've configured with: https://www.googleapis.com/oauth2/v1/tokeninfo?access_token=
It might be worth dumping out the request to make sure there isn't a mistake in that (e.g. too short a content-length header or similar).
Dumping the request is key. To help , here is one I baked earlier..
==POST==
https://accounts.google.com/o/oauth2/token
refresh_token=1/_PEzU2m71wertwertwerJUtrtrytrytryf3trytryoCo
&client_id=612222222225
&client_secret=Q7334534543534yKLu
&grant_type=refresh_token
Are you using the short form of the client id, ie. just the number?
I'm having a problem with the paypal IPN callback. Paypal's IPN callback stopped working, in sandbox environment.
I've been testing my client's website, for the past weeks, and it has always been working correctly - The payment was made, and a callback IPN was sent back to the website, confirming the payment, and updating the website's database.
I haven´t change anything in my code, and it suddenly stopped working. The payment is still made and saved in the paypal account, but the IPN is always retrying... it doesn't complete.
Here's the code in use:
<?php
// STEP 1: read POST data
// Reading POSTed data directly from $_POST causes serialization issues with array data in the POST.
// Instead, read raw POST data from the input stream.
$raw_post_data = file_get_contents('php://input');
$raw_post_array = explode('&', $raw_post_data);
$myPost = array();
foreach ($raw_post_array as $keyval) {
$keyval = explode ('=', $keyval);
if (count($keyval) == 2)
$myPost[$keyval[0]] = urldecode($keyval[1]);
}
// read the IPN message sent from PayPal and prepend 'cmd=_notify-validate'
$req = 'cmd=_notify-validate';
if(function_exists('get_magic_quotes_gpc')) {
$get_magic_quotes_exists = true;
}
foreach ($myPost as $key => $value) {
if($get_magic_quotes_exists == true && get_magic_quotes_gpc() == 1) {
$value = urlencode(stripslashes($value));
} else {
$value = urlencode($value);
}
$req .= "&$key=$value";
}
// STEP 2: POST IPN data back to PayPal to validate
$ch = curl_init('https://www.sandbox.paypal.com/cgi-bin/webscr');
curl_setopt($ch, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_1);
curl_setopt($ch, CURLOPT_POST, 1);
curl_setopt($ch, CURLOPT_RETURNTRANSFER,1);
curl_setopt($ch, CURLOPT_POSTFIELDS, $req);
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, 1);
curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, 2);
curl_setopt($ch, CURLOPT_FORBID_REUSE, 1);
curl_setopt($ch, CURLOPT_HTTPHEADER, array('Connection: Close'));
// In wamp-like environments that do not come bundled with root authority certificates,
// please download 'cacert.pem' from [link removed] and set
// the directory path of the certificate as shown below:
// curl_setopt($ch, CURLOPT_CAINFO, dirname(__FILE__) . '/cacert.pem');
if( !($res = curl_exec($ch)) ) {
// error_log("Got " . curl_error($ch) . " when processing IPN data");
curl_close($ch);
exit;
}
curl_close($ch);
……
?>
Firing some outputs to text files, I discovered that it passes the first Step and stops on the Second, before
if( !($res = curl_exec($ch)) ) {
I've already submitted three help requests to PayPal, but still didn't get an answer from them.
The cURL request initiates a HTTP POST back to PayPal in order to validate the IPN message. If it stops at this step, it means you do receive the IPN POST from PayPal, but you've got a problem connecting back to PayPal.
What does // error_log("Got " . curl_error($ch) . " when processing IPN data"); contain?
In order to resolve this, test the HTTPS connection from your server to the following addresses:
https://www.paypal.com/cgi-bin/webscr?cmd=_notify-validate
https://www.sandbox.paypal.com/cgi-bin/webscr?cmd=_notify-validate
For example, you can run cURL directly from your server (assuming you've got SSH access);
curl -v https://www.sandbox.paypal.com/cgi-bin/webscr?cmd=_notify-validate
This should return something similar to the following:
$ curl -v https://www.sandbox.paypal.com/cgi-bin/webscr?cmd=_notify-validate
* About to connect() to www.sandbox.paypal.com port 443 (#0)
* Trying 173.0.82.77...
* connected
* Connected to www.sandbox.paypal.com (173.0.82.77) port 443 (#0)
* successfully set certificate verify locations:
* CAfile: /usr/ssl/certs/ca-bundle.crt
CApath: none
* SSLv3, TLS handshake, Client hello (1):
* SSLv3, TLS handshake, Server hello (2):
* SSLv3, TLS handshake, CERT (11):
* SSLv3, TLS handshake, Server finished (14):
* SSLv3, TLS handshake, Client key exchange (16):
* SSLv3, TLS change cipher, Client hello (1):
* SSLv3, TLS handshake, Finished (20):
* SSLv3, TLS change cipher, Client hello (1):
* SSLv3, TLS handshake, Finished (20):
* SSL connection using AES256-SHA
* Server certificate:
* subject: 1.3.6.1.4.1.311.60.2.1.3=US; 1.3.6.1.4.1.311.60.2.1.2=Delaware; businessCategory=Private Organization; serialNumber=3014267; C=US; postalCode=95131-2021; ST=California; L=San Jose; street=2211 N 1st St; O=PayPal, Inc.; OU=PayPal Production; CN=www.sandbox.paypal.com
* start date: 2011-09-01 00:00:00 GMT
* expire date: 2013-09-30 23:59:59 GMT
* common name: www.sandbox.paypal.com (matched)
* issuer: C=US; O=VeriSign, Inc.; OU=VeriSign Trust Network; OU=Terms of use at https://www.verisign.com/rpa (c)06; CN=VeriSign Class 3 Extended Validation SSL CA
* SSL certificate verify ok.
> GET /cgi-bin/webscr?cmd=_notify-validate HTTP/1.1
> User-Agent: curl/7.28.1
> Host: www.sandbox.paypal.com
> Accept: */*
>
* HTTP 1.1 or later with persistent connection, pipelining supported
< HTTP/1.1 200 OK
< Date: Wed, 14 Aug 2013 20:15:53 GMT
< Server: Apache
< X-Frame-Options: SAMEORIGIN
< Set-Cookie: xxxxx
< X-Cnection: close
< Set-Cookie: xxxx domain=.paypal.com; path=/; Secure; HttpOnly
< Set-Cookie: Apache=10.72.128.11.1376511353229960; path=/; expires=Fri, 07-Aug-43 20:15:53 GMT
< Vary: Accept-Encoding
< Strict-Transport-Security: max-age=14400
< Transfer-Encoding: chunked
< Content-Type: text/html; charset=UTF-8
<
* Connection #0 to host www.sandbox.paypal.com left intact
**INVALID* Closing connection #0**
* SSLv3, TLS alert, Client hello (1):
If you receive a timeout or an SSL handshake error, you will need to investigate this separately.
I am creating my own php bosh connector so I
can attach() to strophe. Here is my exchange and I'm getting a Bad
Authentication error (which is a google specific error). The exchanges seem to be exactly the same as within
strophe when I connect with strophe successfully, do you know what is the problem?
<body rid='5559198240000' xmlns='http://jabber.org/protocol/httpbind'
to='babson.edu' xml:lang='en' wait='60' hold='1' window='5'
content='text/xml; charset=utf-8' ver='1.6' xmpp:version='1.0'
xmlns:xmpp='urn:xmpp:xbosh'/>
string(500) "<body xmlns='http://jabber.org/protocol/httpbind'
inactivity='60' secure='true' authid='BECF5BCD50577C01' content='text/xml;
charset=utf-8' window='5' polling='15'
sid='4ad843a8e15c79e34976783c96785bd5' requests='2'
wait='60'><stream:features xmlns:stream='http://etherx.jabber.org/streams'
xmlns='jabber:client'><mechanisms
xmlns='urn:ietf:params:xml:ns:xmpp-sasl'><mechanism>PLAIN</mechanism><mecha
nism>X-GOOGLE-TOKEN</mechanism><mechanism>X-OAUTH2</mechanism></mechanisms>
</stream:features></body>"
<body rid='5559198240001' xmlns='http://jabber.org/protocol/httpbind'
sid='4ad843a8e15c79e34976783c96785bd5'><auth
xmlns='urn:ietf:params:xml:ns:xmpp-sasl'
mechanism='PLAIN'>same_base_64_translated_string_as_in_strophe=</auth></bod
y>
string(24) "Error=BadAuthentication
I've checked and the base_64 SASL encoded string is exactly the same as in my strophe logs where I connect successfully. But my php program sending the same exact xml gets this BadAuthentication error.
I was using the wrong curl headers:
this is the correct way to use curl to speak with BOSH for anybody else that finds this post:
$ch = curl_init($bosh_url);
curl_setopt($ch, CURLOPT_HEADER, 0);
curl_setopt($ch, CURLOPT_POST, 1);
curl_setopt($ch, CURLOPT_POSTFIELDS, $xmlpost);
curl_setopt($ch, CURLOPT_FOLLOWLOCATION, true);
$header = array('Accept-Encoding: gzip, deflate','Content-Type: text/xml; charset=utf-8');
curl_setopt($ch, CURLOPT_HTTPHEADER, $header );
curl_setopt($ch, CURLOPT_VERBOSE, 0);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
$response = curl_exec($ch);
var_dump($response);