Discourse signing parameters in webhooks

AI-generated summary

The discussion revolves around adding a secure authentication mechanism to Discourse webhooks. EGreg proposed using public-private key support or a symmetric secret key to verify the signed payload. simon suggested using the Webhook Secret key, which can be verified using a PHP implementation, as seen in the WP Discourse plugin. This plugin uses the hash_hmac function to verify the signature of the payload, ensuring the data comes from Discourse and has not been tampered with.

Hey. I would like to use Discourse webhooks for when a user is created or updated, but I would like to be able to trust the data sent over by Discourse. Any way we could have at a public-private key support, or at least a symmetric secret key, that I can use to verify the signed payload? Can we have some standard framework for signing all the payloads and a standard PHP implementation, say, to serialize and verify the signature?

Facebook does it when it sends over the information about a user. This would allow other software to integrate with Discourse users and other objects.

Does the Webhook Secret key come close to what you are looking for? Here’s how the WP Discourse plugin verifies it against the Webhook Secret that gets set on WordPress:

public function verify_discourse_webhook_request( $data ) {
	$options = $this->get_options();
	// The X-Discourse-Event-Signature consists of 'sha256=' . hamc of raw payload.
	// It is generated by computing `hash_hmac( 'sha256', $payload, $secret )`.
	$sig = substr( $data->get_header( 'X-Discourse-Event-Signature' ), 7 );
	if ( $sig ) {
		$payload = $data->get_body();
		// Key used for verifying the request - a matching key needs to be set on the Discourse webhook.
		$secret = ! empty( $options['webhook-secret'] ) ? $options['webhook-secret'] : '';

		if ( ! $secret ) {

			return new \WP_Error( 'discourse_webhook_configuration_error', 'The webhook secret key has not been set.' );
		}

		if ( hash_hmac( 'sha256', $payload, $secret ) === $sig ) {

			return $data;
		} else {

			return new \WP_Error( 'discourse_webhook_authentication_error', 'Discourse Webhook Request Error: signatures did not match.' );
		}
	}

	return new \WP_Error( 'discourse_webhook_authentication_error', 'Discourse Webhook Request Error: the X-Discourse-Event-Signature was not set for the request.' );
}
3 Likes