Am getting 'Unable to extract timestamp and signatures from header' error when using Stripe webhook in PHP
Asked Answered
S

2

6

I am migrating a site from using Stripe Checkout v2 to v3 using the client side PHP code (everything here in test mode). I have successfully setup the checkout process and after payment get redirected to the success page.

On the success page I have put the webhook code as I want to validate the payment has been made, then display a form.

The webhook has been setup in the Stripe Dashboard, and is showing as "Succeeded" in the webhook logs.

Here is the PHP code for the checkout:

require('includes/stripe/stripe-v3/init.php');

\Stripe\Stripe::setApiKey('sk_test_...');

$session = \Stripe\Checkout\Session::create([
  'payment_method_types' => ['card'],
  'line_items' => [[
    'name' => 'Example',
    'description' => 'Example description',
    'images' => ['https://example/com/image.png'],
    'amount' => 99,
    'currency' => 'gbp',
    'quantity' => 1,
  ]],
  'success_url' => 'https://example.com/test-payment.php?checkout=v3&payment=success&session_id={CHECKOUT_SESSION_ID}',
  'cancel_url' => 'https://example.com/test-payment?payment=failed',
]);

$session_id = $session->id;

And here's the JavaScript:

var stripe = Stripe('pk_test_4iEnGexyFSJgXFumnmEXWDlG');
function checkout_redirect() {
    stripe.redirectToCheckout({
      // Make the id field from the Checkout Session creation API response
      // available to this file, so you can provide it as parameter here
      // instead of the {{CHECKOUT_SESSION_ID}} placeholder.
      sessionId: '<?php echo $session_id; ?>'
    }).then(function (result) {
      // If `redirectToCheckout` fails due to a browser or network
      // error, display the localized error message to your customer
      // using `result.error.message`.
    });
}

Then this is the code to validate the webhook within test-payment.php:

require('includes/stripe/stripe-v3/init.php');

\Stripe\Stripe::setApiKey('sk_test_...');

$endpoint_secret = 'whsec_...';

$payload = @file_get_contents('php://input');
$sig_header = $_SERVER['HTTP_STRIPE_SIGNATURE'];
$event = null;

try {
  $event = \Stripe\Webhook::constructEvent(
    $payload, $sig_header, $endpoint_secret
  );
} catch(\UnexpectedValueException $e) {
  // Invalid payload
  http_response_code(400); // PHP 5.4 or greater
  exit();
} catch(\Stripe\Error\SignatureVerification $e) {
  // Invalid signature
  http_response_code(400); // PHP 5.4 or greater
  exit();
}

// Handle the checkout.session.completed event
if ($event->type == 'checkout.session.completed') {
  $session = $event->data->object;

  // Fulfill the purchase...
  handle_checkout_session($session);
}

http_response_code(200);

When being redirected to test-payment.php it's failing on the "SignatureVerification" with the following error:

exception 'Stripe\Error\SignatureVerification' with message 'Unable to extract timestamp and signatures from header'

I have tried to echo $_SERVER['HTTP_STRIPE_SIGNATURE'] but it's empty, so I'm thinking that might be the problem but am stumped on how to fix it.

Any ideas guys? Or is there an easier way to validate a payment has been made?

Slipway answered 7/8, 2019 at 10:28 Comment(0)
I
2

the problem is when parsing the sigHeader. the header value is [t=1571998117,v1=ba786269057f295aa2a67795f7a70e07f71ff8eb4f5a24ecde0721453a09a461,v0=2d3802ff7fd896b7c4c01b297997e126405e5e2af7938b7ae2a28c11f3ef0d8f]

before pass to constuct(), need to trim '[' and ']' off.

Codes:

String signature = headers.get(HEADER_STRIPE_SIGNATURE);
signature = trimSignature(signature)    
Event event = StripeUtil.constructEvent(request, signature, key)
Imbecility answered 25/10, 2019 at 10:29 Comment(0)
R
0

In my case I had the same error because I was look for the signature in HTTP_STRIPE_SIGNATURE header but the correct header name to look is stripe-signature.

Reimpression answered 22/7, 2022 at 14:16 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.