Skip to content

Fix for issue #104: Verify webhook by civicrm - #105

Open
jaapjansma wants to merge 7 commits into
systopia:mainfrom
jaapjansma:dev_104
Open

Fix for issue #104: Verify webhook by civicrm#105
jaapjansma wants to merge 7 commits into
systopia:mainfrom
jaapjansma:dev_104

Conversation

@jaapjansma

Copy link
Copy Markdown
Contributor

This PR solves issue #104

It adds the following functionality:

  • ability to verify an incoming webhook request by civicrm. It does so to send an additional verification api to CiviCRM. The CiviCRM api succeeds or fails, if it succeeds the request is valid. If it fails the request is invalid

The reason for doing the verification in CiviCRM is that for HMAC verification we need a secret key to do the verification and we do not want to have too many secrets on the proxy.

This PR also solves one bug with the Request class not containing all headers.

Comment thread proxy/config.dist.php
Comment thread proxy/config.dist.php
Comment thread proxy/webhook2api.php Outdated
Comment thread src/Api/Request.php Outdated
$this->request = $request;
$this->files = $files;
$this->server = $server;
foreach(getallheaders() as $header => $headerValue) {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why is the call of getallheaders() is necessary? Doesn't all the headers come in the $server argument?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It is needed because depending on the webser (nginx vs apache) not all headers are in $_SERVER. For example on my local apache webserver. Te $_SERVER did not have the Authorization header. Which is one we needed for our specific use case

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Seems to be an Apache issue that could be solved by adding SetEnvIf Authorization "(.*)" HTTP_AUTHORIZATION=$1 to .htaccess or the Apache config.

Though if the code should work without that I'd suggest to put the call of getallheaders() into Request::createFromGlobals() with an explaining comment.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I have added a comment to explain why we use getallheaders.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

👍 I still think that it shouldn't be part of the constructor so that it might be possible to create request objects without relying on that function, e.g. in unit tests. Now that there's a create() method I'd put it there.

@jaapjansma
jaapjansma requested a review from dontub July 23, 2026 14:07
Comment thread proxy/proxy.php Outdated
Comment thread src/Api/Request.php Outdated
$this->request = $request;
$this->files = $files;
$this->server = $server;
foreach(getallheaders() as $header => $headerValue) {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

👍 I still think that it shouldn't be part of the constructor so that it might be possible to create request objects without relying on that function, e.g. in unit tests. Now that there's a create() method I'd put it there.

@jaapjansma

Copy link
Copy Markdown
Contributor Author

@dontub can you do another review? I made some changes as you suggested them.

Comment thread proxy/webhook2api.php Outdated
Comment thread proxy/webhook2api.php Outdated
Comment thread src/Api/Request.php
foreach ($server as $header => $headerValue) {
if (stripos($header, 'HTTP_') === 0) {
$this->headers[substr($header, 5)] = $headerValue;
$key = str_replace(' ', '-', ucwords(strtolower(str_replace('_', ' ', substr($header, 5)))));

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Was this added for the headers from getallheaders()? If so, its not applied to those headers with the latest change anymore.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ah yes that change is not needed anymore.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think it's necessary for the headers from getallheaders(). In $_SERVER the key is for example HTTP_CONTENT_LENGTH while in getallheaders() it's Content-Length, isn't it?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes it is. You are right

@jensschuppe jensschuppe linked an issue Aug 6, 2026 that may be closed by this pull request
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

HMAC for webhooks

2 participants