Reputation: 2083
Referencing the answer here: PHP verify Paypal webhook signature
Is this still the working solution for today (Jan '22)? Curious why it says on github.com/paypal/PayPal-PHP-SDK that this package is deprecated? (and archived)?
Upvotes: 2
Views: 2959
Reputation: 3638
I have just done this for wordpress, feel free to alter for your needs.
make sure you create your webhook in your dashboard with the events you need, and get the ID from it to use.
Create a function to generate auth tokens for paypal:
function paypal_access_token() {
$clientID = 'PAYPAL_CLIENT_ID';
$clientSecret = 'PAYPAL_SECRET_key';
$auth = base64_encode( $clientID . ':' . $clientSecret );
$cacheKey = 'PAYPAL_ACCESS_TOKEN_' . $clientID;
$token = get_transient($cacheKey);
if ($token === false){
$body = [
'grant_type' => 'client_credentials',
];
$credential_post = wp_remote_post(
'https://api-m.sandbox.paypal.com/v1/oauth2/token',
array(
'method' => 'POST',
'headers' => array(
'Authorization' => "Basic $auth",
'Content-Type' => 'application/x-www-form-urlencoded',
),
'body' => urlencode_deep( $body ),
)
);
$result = wp_remote_retrieve_body( $credential_post );
$token = json_decode($result, true);
set_transient($cacheKey, $token['access_token'], ($token['expires_in'] - 60));
$token = $token['access_token'];
}
return $token;
}
then create a verify event function:
function paypal_verify_webhook($args){
$token = paypal_access_token();
$paypal_post = wp_remote_post(
'https://api-m.sandbox.paypal.com/v1/notifications/verify-webhook-signature',
array(
'method' => 'POST',
'headers' => array(
'Content-Type' => 'application/json',
'Authorization' => "Bearer $token",
),
'body' => wp_json_encode( $args, JSON_UNESCAPED_SLASHES ),
)
);
$paypal_response = wp_remote_retrieve_body( $paypal_post );
if ( !is_wp_error( $paypal_response ) ) {
return $paypal_response;
}
return false;
}
and finally the webhook file itself:
$requestBody = file_get_contents('php://input');
if(!$requestBody) {
exit();
}
$headers = getallheaders();
$headers = array_change_key_case($headers, CASE_UPPER);
if(
(!array_key_exists('PAYPAL-AUTH-ALGO', $headers)) ||
(!array_key_exists('PAYPAL-TRANSMISSION-ID', $headers)) ||
(!array_key_exists('PAYPAL-CERT-URL', $headers)) ||
(!array_key_exists('PAYPAL-TRANSMISSION-SIG', $headers)) ||
(!array_key_exists('PAYPAL-TRANSMISSION-TIME', $headers))
)
{
exit();
}
$webhook_id = 'WEBHOOK_ID_FROM_DASHBOARD';
$args = array(
'auth_algo' => $headers['PAYPAL-AUTH-ALGO'],
'cert_url' => $headers['PAYPAL-CERT-URL'],
'transmission_id' => $headers['PAYPAL-TRANSMISSION-ID'],
'transmission_sig' => $headers['PAYPAL-TRANSMISSION-SIG'],
'transmission_time' => $headers['PAYPAL-TRANSMISSION-TIME'],
'webhook_id' => $webhook_id,
'webhook_event' => json_decode($requestBody)
);
$verify_webhook = paypal_verify_webhook($args);
$verify_status = json_decode($verify_webhook, true);
if( isset($verify_status['verification_status'] ) && $verify_status['verification_status'] === "SUCCESS"){
$data = json_decode($requestBody, true);
if (isset($data['event_type'])) {
$event_type = $data['event_type'];
switch ($event_type) {
case 'CHECKOUT.ORDER.COMPLETED':
// Do Stuff...
break;
case 'PAYMENT.SALE.COMPLETED':
// Do Stuff...
break;
// Add more cases etc...
default:
// Do Stuff...
break;
}
}
http_response_code(200);
exit();
}
else{
exit();
}
Upvotes: 1
Reputation: 31
This is how i verify the call from PayPal to my webhook with PHP:
$success = (
openssl_verify(
data: implode(separator: '|', array: [
$httpPayPalTransmissionId,
$httpPayPalTransmissionTime,
$webhookID,
crc32(string: $rawRequestBody),
]),
signature: base64_decode(string: $httpPayPalTransmissionSignature),
public_key: openssl_pkey_get_public(public_key: file_get_contents(filename: $httpPayPalCertUrl)),
algorithm: 'sha256WithRSAEncryption'
) === 1
);
Upvotes: 1
Reputation: 30457
That SDK is deprecated and not maintained. There is no support for it.
There are two supported ways to verify a webhook, either post it back to an API endpoint, or verifying the cryptographic message signature yourself.
Neither document is specific to PHP, but has the information necessary to adapt into your own implementation in any language.
Upvotes: 0