Answered

Secure your webhooks (PHP)


Userlevel 2
Badge +1

Hi

I read this: https://developer.typeform.com/webhooks/secure-your-webhooks/ and this: https://developer.typeform.com/webhooks/reference/create-or-update-webhook/
 

In the RESPONSE of this page:https://developer.typeform.com/webhooks/reference/create-or-update-webhook/ I see a SECRET string.

 

But in my Payload response I do not have this string?

I only get this:

stdClass Object(    [form_id] => FvKcTWd8    [token] => wpdnrrxmzwcsw3advzwpdnrrk8c793jl    [landed_at] => 2022-04-14T08:25:18Z    [submitted_at] => 2022-04-14T08:26:20Z    [hidden] => stdClass Object        (            [bu] => DEMAT            [formulaire] => FRM_TF_REPLAY_WEBINAR        )    [definition] => stdClass Object        (            [id] => FvKcTWd8            [title] => REPLAY WEBINAR DEMAT            [fields] => Array                (                    [0] => stdClass Object                        (                            [id] => piorTyjypJn9                            [ref] => connais-dimo                            [type] => yes_no                            [title] => Connaissiez-vous DIMO Software avant de recevoir notre invitation pour le replay ?                             [properties] => stdClass Object                                (                                )                        )                    [1] => stdClass Object                        (                            [id] => c30vG0KfxtMu                            [ref] => prenom                            [type] => short_text                            [title] => Quel est votre prénom ?                            [properties] => stdClass Object                                (                                )                        )                    [2] => stdClass Object                        (                            [id] => Cy1MzLWc099v                            [ref] => nom                            [type] => short_text                            [title] => Votre nom ?                            [properties] => stdClass Object                                (                                )                        )                    [3] => stdClass Object                        (                            [id] => nBb7J2c6g4ZG                            [ref] => societe                            [type] => short_text                            [title] => Et votre société ?                             [properties] => stdClass Object                                (                                )                        )                    [4] => stdClass Object                        (                            [id] => EfXsC7rYhAuy                            [ref] => projet                            [type] => yes_no                            [title] => Avez-vous un projet de dématérialisation des factures fournisseurs ?                             [properties] => stdClass Object                                (                                )                        )                    [5] => stdClass Object                        (                            [id] => aXjgPl40yt1N                            [ref] => projet-precision                            [type] => short_text                            [title] => Une précision sur votre projet ?                             [properties] => stdClass Object                                (                                )                        )                    [6] => stdClass Object                        (                            [id] => EhAmGPOS9eQi                            [ref] => quand-contact                            [type] => multiple_choice                            [title] => Quand nous conseillez-vous de vous contacter à ce sujet ?                             [properties] => stdClass Object                                (                                )                            [choices] => Array                                (                                    [0] => stdClass Object                                        (                                            [id] => ZGHUEclsgNlZ                                            [label] => Dans les prochains jours                                        )                                    [1] => stdClass Object                                        (                                            [id] => LsXqwZtWCe4v                                            [label] => Moins de 3 mois                                        )                                    [2] => stdClass Object                                        (                                            [id] => 31JPP5BWeXPc                                            [label] => Moins de 6 mois                                        )                                    [3] => stdClass Object                                        (                                            [id] => dONPTsq3zNek                                            [label] => Plus de 6 mois                                        )                                    [4] => stdClass Object                                        (                                            [id] => y7JrXvcrQd8l                                            [label] => Je ne sais pas                                        )                                )                        )                )        )    [answers] => Array        (            [0] => stdClass Object                (                    [type] => boolean                    [boolean] =>                     [field] => stdClass Object                        (                            [id] => piorTyjypJn9                            [type] => yes_no                            [ref] => connais-dimo                        )                )            [1] => stdClass Object                (                    [type] => text                    [text] => Jean                    [field] => stdClass Object                        (                            [id] => c30vG0KfxtMu                            [type] => short_text                            [ref] => prenom                        )                )            [2] => stdClass Object                (                    [type] => text                    [text] => Dujardin                    [field] => stdClass Object                        (                            [id] => Cy1MzLWc099v                            [type] => short_text                            [ref] => nom                        )                )            [3] => stdClass Object                (                    [type] => text                    [text] => La Grande Jardinerie                    [field] => stdClass Object                        (                            [id] => nBb7J2c6g4ZG                            [type] => short_text                            [ref] => societe                        )                )            [4] => stdClass Object                (                    [type] => boolean                    [boolean] => 1                    [field] => stdClass Object                        (                            [id] => EfXsC7rYhAuy                            [type] => yes_no                            [ref] => projet                        )                )            [5] => stdClass Object                (                    [type] => text                    [text] => Rae le bol des fournisseurs qui ne payent pas !                    [field] => stdClass Object                        (                            [id] => aXjgPl40yt1N                            [type] => short_text                            [ref] => projet-precision                        )                )            [6] => stdClass Object                (                    [type] => choice                    [choice] => stdClass Object                        (                            [label] => Je ne sais pas                        )                    [field] => stdClass Object                        (                            [id] => EhAmGPOS9eQi                            [type] => multiple_choice                            [ref] => quand-contact                        )                )        ))

 

icon

Best answer by Pako69 20 April 2022, 09:53

View original

18 replies

Userlevel 7
Badge +5

@mathio do you happen to know what’s going on here? 😯

Userlevel 7
Badge +5

Hi @Pako69 

Thank you for your question!

I think you are looking at different things.

Case #1: Use webhook to be notified of new response on your typeform
You can create this webhook manually from Typeform’s builder. This webhook points to the URL of your choice. If you want to secure this webhook connection you can add a secret as explained here.

Every time we will send a webhook event to you we will use this secret to sign the request. So on your end you can verify that the request is legit and comes from Typeform.
We will send the signature in a header called Typeform-Signature.

Case #2: You want to programmatically create webhooks

Using the Webhook API you can attach webhooks to forms. And the same way you could do in the UI, you could specify a secret to sign webhook payloads.

Hope this makes sense.

Userlevel 2
Badge +1

hi @picsoung 

 

Thanks I was not aware of the sent headers, now I know where I must look at :-)

 

But I’m stuck with the second part of the process of the documentation :

----

Validate payload from Typeform

To validate the signature you received from Typeform, you will generate the signature yourself using your secret and compare that signature with the signature you receive in the webhook payload.

  1. Using the HMAC SHA-256 algorithm, create a hash (using created_token as a key) of the entire received payload as binary.
  2. Encode the binary hash in base64 format.
  3. Add prefix sha256= to the binary hash.
  4. Compare the created value with the signature you received in the Typeform-Signature header from Typeform.

 

Because I dot not use Ruby, Python, etc. but just PHP :-(

 

Would be great to have exemples with famous language too…

 

Thanks

 

Userlevel 2
Badge +1

I tried this:

 

$typeform_signature = $_SERVER['HTTP_TYPEFORM_SIGNATURE'];

$secret = '0e6ac685e21c8816e2a1c4482dc0a6f28c87e483';

$base64_encoded_hash = base64_encode(hash_hmac('sha256', $typeform_signature, $secret, true));

 

But when I compare the value of $typeform_signature with $base64_encoded_hash the two values do not match :-(

Examples :

$typeform_signature:
sha256=HYToAdlWtXFx/fd1YHIidLfruxh62vWQufVhqtm9DrE=

$base64_encoded_hash:
sha256=skQ010FyjJna3VXjstqc1mUbAUuxEBCLryhpoKQGcng=

 

Userlevel 2
Badge +1

Is there anyone who can help me with this?

Thanks

Userlevel 7
Badge +6

@Pako69 - have you raised a help ticket with the Typeform Support team yet?? 

 

if not use this link

Userlevel 2
Badge +1

@Pako69 - have you raised a help ticket with the Typeform Support team yet?? 

 

if not use this link

I will...

Userlevel 2
Badge +1

Here is the solution in pure PHP :-)

$datas              = file_get_contents("php://input");

$typeformSignature  = $_SERVER['HTTP_TYPEFORM_SIGNATURE'];

$key                = 'xe6ac685e21c8816e2a1c4482dc0a6f28c87e483';

$hashed             = hash_hmac('sha256', $datas, $key, $raw_output = TRUE);

$base64             = base64_encode($hashed);

$endValue           = "sha256=". $base64;

if($typeformSignature === $endValue){

        echo 'Well done bro!';

     } else {

        echo 'Sorry bro!';

        return;

     }  
  

Userlevel 7
Badge +5

Amazing, @Pako69! Were you able to get to this solution because of the ticket you have raised with our Support team? 

Userlevel 2
Badge +1

Amazing, @Pako69! Were you able to get to this solution because of the ticket you have raised with our Support team? 

 

Yes, the support team send me here: https://stackoverflow.com/questions/56133602/signature-in-ruby-to-php

 

Userlevel 7
Badge +5

Ah that's cool, thanks for sharing! @Pako69 So now can you confirm this is working?

Userlevel 2
Badge +1

Ah that's cool, thanks for sharing! @Pako69 So now can you confirm this is working?

Yes

Userlevel 7
Badge +5

Yay, amazing @Pako69! Last but not least, why don't you share with us some of your forms? We'd love to take a look at it and give some feedback! 😉

Hello, I m using Laravel9 with php8, I am trying to authenticate the call from Typeform using similar  algorithm than @Pako69 but it doesn’t work, I get different results than the one sent from Typeform:

Typeform
sha256=cpNlqTi1+pYkTIAmfZs4s1hz0ntYn3bjJMHdCL6mPaU=

My code returns:

sha256=NdobD56ZvX/+vRqGyLviBH7nIyIC5FxxRZhjnlwuDgM=

This is my code:

$secret=config('app.TYPEFORM_WEBHOOK_SECRET');
$signature = $request->header('Typeform-Signature');
$payload = @file_get_contents('php://input');
$expectedSignature = 'sha256='.base64_encode(hash_hmac('sha256',$payload,$secret,true));

there is something I need to do with the payload? Any ideas?

Thanks in advance!

Userlevel 7
Badge +5

@picsoung or @mathio do either of you happen to know what the issue might be for @gusberte 

I am also experiencing the same issue as @gusberte using the same stack Laravel 9 and php8.1. 

Our code is similar (I’ve tried file_get_contents also):

$payload = $request->getContent();
$secret = env('TYPEFORM_SECRET');
$hashed = hash_hmac(
'sha256',
$payload,
$secret,
true, // binary format
);

$base64encoded = "sha256=".base64_encode($hashed);
return $base64encoded === $request->header('Typeform-Signature');

 

Userlevel 7
Badge +5

@mathio do you happen to know anything about this php code? 😑

Userlevel 7
Badge +5

Hello all,

let’s have a look together.

  1. I setup a webhook for my typeform via Connect tab in admin UI:
Creating webhook via UI
  1. Then I added secret:
Webhook secured (domain is obviously not example.com)
  1. I used code from @gusberte with some modifications:
<?php

echo 'php version: '.phpversion()."\n";

$headers = getallheaders();
$header_signature = $headers['Typeform-Signature'];

$payload = @file_get_contents('php://input');
$secret = 'mysecret!!1';
$hashed_payload = hash_hmac('sha256', $payload, $secret, true);
$base64encoded = "sha256=".base64_encode($hashed_payload);

echo 'header signature: '.$header_signature."\n";
echo 'request signature: '.$base64encoded."\n";

if ($header_signature === $base64encoded) {
echo "success!\n";
}
  1. I sent the test request from admin UI and it worked:
Request successfully validated

I tried with PHP 7.3 and 8.1, both worked fine.

Reply