skip to Main Content

I have successfully implemented webhook integration using Sandbox in Paypal.
Now I want to make it more secure so that only Paypal signed notification is accepted.
I was trying to verify webhook signature using

https://developer.paypal.com/docs/api/webhooks/v1/#verify-webhook-signature_post

But it always returns FAILURE.

The request is :

{"auth_algo":"SHA256withRSA","transmission_time":"2020-08-17T12:11:08Z","cert_url":"https://api.sandbox.paypal.com/v1/notifications/certs/CERT-360caa42-fca2a594-1d93a270","webhook_id":"0JD18557VD498931R","transmission_id":"bbaae190-e082-11ea-aa52-1fdbf2bc8461","webhook_event":{"summary":"Payment completed for $ 5.0 USD","event_type":"PAYMENT.SALE.COMPLETED","create_time":"2020-08-17T12:11:05.015Z","resource":{"billing_agreement_id":"I-DNVD3H9UWYHL","amount":{"total":"5.00","currency":"USD","details":{"subtotal":"5.00"}},"payment_mode":"INSTANT_TRANSFER","update_time":"2020-08-17T12:10:39Z","create_time":"2020-08-17T12:10:39Z","protection_eligibility_type":"ITEM_NOT_RECEIVED_ELIGIBLE,UNAUTHORIZED_PAYMENT_ELIGIBLE","transaction_fee":{"currency":"USD","value":"0.45"},"protection_eligibility":"ELIGIBLE","links":[{"method":"GET","rel":"self","href":"https://api.sandbox.paypal.com/v1/payments/sale/8TV124151P468690Y"},{"method":"POST","rel":"refund","href":"https://api.sandbox.paypal.com/v1/payments/sale/8TV124151P468690Y/refund"}],"id":"8TV124151P468690Y","state":"completed","invoice_number":""},"resource_type":"sale","links":[{"href":"https://api.sandbox.paypal.com/v1/notifications/webhooks-events/WH-2XT265922L1486124-74F09092JL7840709","rel":"self","targetSchema":null,"method":"GET","enctype":null,"schema":null},{"href":"https://api.sandbox.paypal.com/v1/notifications/webhooks-events/WH-2XT265922L1486124-74F09092JL7840709/resend","rel":"resend","targetSchema":null,"method":"POST","enctype":null,"schema":null}],"id":"WH-2XT265922L1486124-74F09092JL7840709"},"transmission_sig":"RYILWohVPkK0hUrMjTSU3+fCgd6NTgqkjrZtsOJiC7FR3U3atOK1k29/Md8DQRReAicdfOpXrS7E4vrvB17HOM39w/D3i4Ohy34HL3CqSsZovL69lhfFmviCGkXjjSbkBhpKGJvQAB4q0E9AWl/SBZc4MUNGezIbk/laJZ6ikQuwGeEHCFaPVrza7kSlZRo03lM9sYSb7q3ixewYmz8voKIyJ2RYjOgsAohNFWgovtKwG+ac66YCp3ZRJLe4fL2Q1UaEDn5BnUhK+5Q2+EqD+BixpqNTuSmYqRwkyDTdrH1EPV5DRU4uYM0gJLXnBovGaqHe8JujpVs+dJu4Mrmgdg=="}

and the result is

{"verification_status":"FAILURE"}

Can someone help, please !!

2

Answers


  1. If you are getting those values from the webhook simulator as they said in their documentation you can’t verify mock webhooks.

    What I used to do when I need to validate the value because some test need that part it’s that using the smart buttons to generate the request and then catch the response in some webhook.

    Login or Signup to reply.
  2. Verify Paypal webhook notification

    How to verify the authenticity of the notification in php:

    // get request headers
    $headers = apache_request_headers();
    
    // get http payload
    $body = file_get_contents( 'php://input' );
    
    // compose signature string: The third part is the ID of the webhook ITSELF(!),
    // NOT the ID of the webhook event sent. You find the ID of the webhook
    // in Paypal's developer backend where you have created the webhook
    $data =
        $headers['Paypal-Transmission-Id'] . '|' .
        $headers['Paypal-Transmission-Time'] . '|' .
        '<WEBHOOK ID FROM THE DEVELOPER DASHBOARD>' . '|' . crc32( $body );
    
    
    // load certificate and extract public key
    $pubKey = openssl_pkey_get_public( file_get_contents( $headers['Paypal-Cert-Url'] ) );
    $key = openssl_pkey_get_details( $pubKey )['key'];
    
    // verify data against provided signature 
    $result = openssl_verify(
        $data,
        base64_decode( $headers['Paypal-Transmission-Sig'] ),
        $key, 'sha256WithRSAEncryption'
    );
    
    
    if ( $result == 1 ) {
        // webhook notification is verified
    } elseif ( $result == 0 ) {
        // webhook notification is NOT verified
    } else {
        // there was an error verifying this
    };
    

    The transmission id, the transmission date, the webhook id and a CRC over the HTTP body. The first two can be found in the header of the request, the webhook id in the developer backend (of course, that id will never change), the CRC is calculated like shown below.

    The certificate’s location is in the header, too, so we load it and extract the private key.

    Last thing to watch out for: The name of the algorithm provided by Paypal (again in a header field) is not exactly the same as understood by PHP. Paypal calls it "sha256WithRSA" but openssl_verify will expect "sha256WithRSAEncryption".

    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search