Webhook Security

Authentication

Upwardli’s webhooks are secured using a Hashed Message Authentication Code (HMAC) in the webhook message header. The name of this header value is upwardli-signature. The upwardli-signature header contains two comma-separated key-value pairs encoding information about the request. The first key-value pair will be in the form t=<unix_timestamp> and represents the unix time that the request was sent. The second key-value pair will be in the form v1=WeNeedSomethingHere, where the signature is a sha256 hash computed from the customer’s webhook secret and a dot-separated string composed of the unix timestamp joined with the request body.

Note: computing the signature is sensitive to the exact characters input into the algortihm. The request data should be a json string with no whitespace formatting.

Sample Data

client_id => 'public'
signature => 't=2023-10-12T20:44:58.082694+00:00,v1=263a5f79d899f7d5e04eb9a902b173d5901a9088966b932edca7174aec3d9e12'
message => '{"id":"954935cb-be33-47a4-99af-ec8bbc662ec7","createdAt":"2023-10-05T17:39:21.097794+00:00","eventName":"consumer_created","partnerId":"cb739356-5f69-429c-8157-756876d08d27","resources":["api/v2/consumers/00000000-0000-0000-0000-000000000000"],"lastAttemptedAt":"2023-10-05T17:39:21.097794+00:00"}'

Example decode in Python

1t, v1 = [value.split('=')[1] for value in request.headers['upwardli-signature'].split(',')]
2computed_digest = hmac.new(<YOUR_CLIENT_ID>.encode(), (t + '.' + request.data.decode('utf-8')).encode(), 'sha256').hexdigest()
3
4if hmac.compare_digest(v1, computed_digest):
5 # Process webhook