Developer
Verifying Signatures
Verifying Signatures
PagerDuty's v3 webhooks are sent with a signature the destination server can use to verify that the event came from the PagerDuty platform and not a third party or malicious system. It is strongly recommended that webhook consumers verify these signatures before processing each event.
Obtaining the Secret
When a webhook subscription is created, a strong unique secret is generated and provided in the response. This secret is used to sign webhook payloads sent as part of this subscription. The signature is then delivered along with each payload under the X-PagerDuty-Signature header.
The Signature
The X-PagerDuty-Signature header included with each webhook event delivery contains one or more signatures. Multiple signatures may be present to allow for a zero-downtime secret rotation.
The current signature version is v1 and is computed as an HMAC of the payload body using a SHA-256 hash function. This is performed for each signing secret and the results are concatenated using comma separation. An example signature is shown below:
X-PagerDuty-Signature:
v1=f03de6f61df6e454f3620c4d6aca17ad072d3f8bbb2760eac3b2ad391b5e8073,
v1=130dcacb53a94d983a37cf2acba98e805a1c37185309ba56fdcccbcf00d6dd8b
(Note that the actual header value is sent as a single string without any new lines.)
Verifying the Signature
A psuedo-algorithm to verify the signature of a webhook delivery is described below.
Step 1: Extract the signature(s) from the request
- Extract the signature string from the
X-PagerDuty-Signatureheader on the request. - Split the signatures which are separated by the
,character. - Select only signatures which are version
v1and remove thev1=prefix.
Step 2: Compute the expected valid signature
Using the received JSON payload (entire request body):
- Compute the SHA-256 HMAC using the shared secret as the key.
- Take the Base16 encoding of the result to obtain a value we can compare.
Step 3: Compare the signatures
Compare the expected signature obtained in Step 2 with the provided signatures from Step 1.
If at least one of the signatures matches, the webhook should be considered a trusted and authentic request from PagerDuty that can be processed by the server.
Note: When comparing signatures, be sure to use a constant-time string comparison to protect against timing attacks.
Verifying PagerDuty webhook signatures requires the unaltered raw body of the request sent to you. Ensure that any frameworks or middleware you are using have not manipulated or formatted the request body.
PagerDuty webhook payloads support unicode characters. If your implementation is converting the request body from string to bytes [or vice-versa], ensure that you are using the proper UTF-8 character encoding.
Examples of webhooks signing
Python
import hmac
import hashlib
class PagerDutyVerifier:
def __init__(self, key, version):
self.key = key
self.version = version
def verify(self, payload, signatures):
comparisons = []
byte_key = self.key.encode("ASCII")
signature = hmac.new(byte_key, payload.encode(), hashlib.sha256).hexdigest()
signatureWithVersion = self.version + "=" + signature
signatureList = signatures.split(",")
for _signature in signatureList:
comparisons.append(hmac.compare_digest(signatureWithVersion, _signature))
return any(comparisons)
pagerdutyVerifier = PagerDutyVerifier(key, version)
pagerdutyVerifier.verify(payload, signatures)
JavaScript
const crypto = require('crypto')
module.exports = class PagerDutyVerifier {
constructor(key, version) {
this.key = key
this.version = version
}
verify(payload, signatures) {
var signature = crypto
.createHmac('sha256', key)
.update(payload)
.digest('hex')
var signatureWithVersion = version + "=" + signature
var signatureList = signatures.split(",")
if (signatureList.indexOf(signatureWithVersion) > -1 ) {
return true
} else {
return false
}
}
}
var PagerDutyVerifier = require('./pagerduty_verifier.js')
var verifier = new PagerDutyVerifier(key, version)
verifier.verify(payload, signatures)
Go
Our go example can be found in our open-source go-pagerduty client library which also comes with a sample webhook server to test signature verification.