In order to authenticate that your publicly exposed endpoint is indeed being called by a Penbox webhook, the HTTP call needs to be authenticated. This can be done by verifying the JWT signature sent along in the HTTP headers. Here are the steps needed to properly authenticate an incoming HTTP request:
Assuming you system is configured with an
<issuer_origin>
equal to https://connect.penbox.io/ in production
First, verify the integrity of the payload
- As the request streams into you server, or after you received the full payload, you can compute its
sha-512
digest. The base64 encoded digest of the (uncompressed) raw body (the plain JSON) must match thedigest
claim from the signature. - For conveniency this digest can also be found in the
[Digest
header](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Digest), allowing to check the validity in two (independent) phases:- Check that the jwt is valid and ensure that its
digest
claim matches the value from theDigest
header. - Ensure that the
sha-512
hash of the http payload matches the value from theDigest
header.
- Check that the jwt is valid and ensure that its
Secondly, verify the authenticity of the HTTP request by validating the JWT contained in the x-pnbx-signature
header.
- The
iss
claim of the JWT payload must exactly match the configured<issuer_origin>
- The
exp
claim, if present, must be a timestamp (seconds since epoch) that is "in the future" wrt. the time at which the HTTP request is being made. - The
nbf
claim, if present, must be a timestamp (seconds since epoch) that is "in the past" wrt. the time at which the HTTP request is being made. - The
aud
claim must exactly match the endpoint being called (your endpoint's public address) - The
method
claim must exactly match the method use by the current HTTP request - The
digest
claim must exactly match the<base64_sha-512_digest>
of the request body. - The signature part of the JWT must be validated against the public key of the issuer.
- The public key can be retrieved in the JWKS format at the following endpoint
<issuer_origin>/.well-known/jwks.json
- You might want to cache this value (respecting the
Cache-Control
header)
- The public key can be retrieved in the JWKS format at the following endpoint
- For additional security, you can protect agains "replays" of the exact same HTTP requests content by ensuring that the value contained in the
jti
claim is a value that was never seen by your server before (no need to keep this value longer than the token'sexp
iration date).