Webhook
Introduction
A webhook is an HTTP request, triggered by an event in a source system and sent to a destination system, often with a payload of data. Webhooks are automated, in other words they are automatically sent out when their event is fired in the source system.
This provides a way for one system (the source) to "speak" (HTTP request) to another system (the destination) when an event occurs, and share information (request payload) about the event that occurred.
Annoto backend is the source and will send messages to the destination platform.
Webhook Security
Annoto will include a secure signature in all the webhook requests so that the destination platform can verify that the webhook request was generated by Annoto, and not from some server acting like Annoto.
Since the signature is specific to each and every webhook request, it also helps to validate that the message wasn’t intercepted and modified by someone in between the destination and the source (i.e. Man-in-the-middle attack).
We will send webhook messages only to valid TLS 1.2 and up (Https) endpoint.
Security Header
Each Webhook message will include a signature header:
X-Annoto-JWS
- A JSON Web Signature (RFC-7797) signed using the Annoto JSON Web Key Set (JWKS / RFC-7517).
The X-Annoto-JWS
signature is a JSON Web Signature (JWS) and has a detached payload. It is a string that looks like JWS_PROTECTED_HEADER..JWS_SIGNATURE
JSON Web Signature (JWS) represents content secured with digital signatures or Message Authentication Codes (MACs) using JSON-based [RFC7159] data structures. The JWS cryptographic mechanisms provide integrity protection for an arbitrary sequence of octets.
The signature generation works as follows:
Webhook message is generated (e.g LTI outcomes)
The payload is signed using one of the private keys from Anntoo's JSON Web Key Set (e.g.
kid: PylK7Us1ntafSdT9RxJ3q
The JWS protected header will contain the following standard properties:
kid
- The key used to sign the request. This can be looked up in the JWKSalg
- Will beRS256
The detached JWS will be added as the
X-Annoto-JWS
header to the Webhook request.The HTTP Request is sent using POST method to the Webhook destination endpoint.
Verifying a Webhook Payload
To verify that a webhook did actually come from Annoto, you need to compare the JSON Web Signature (JWS) from the X-Annoto-JWS
header with the JSON body of the request:
Ensure the
X-Annoto-JWS
header exists. If it doesn't exist, this request didn't come from Annoto.Look up the Annoto JWKS at the URL provided by Annoto. This contains the public keys, and should have a kid that matches the kid of the
JWS_PROTECTED_HEADER
Use a JWT library for your programming language to verify the body matches the signature.
To implement the verification, some languages may require you to build URL variant of Base64 Encode of the JWS Payload (the webhook body) in order to verify the JWS.
The JWS signature uses a detached payload, so it is of the form
JWS_PROTECTED_HEADER..JWS_SIGNATURE
as per RFC the kid for an individual JWK is immutable, and therefore it is safe and recommended to cache individual JWK's by their kid indefinitely (a proper JWT library will probably do that for you).
Example libraries that support RFC-7797 and JWKS, and simplify verifying a JWS:
Java: com.nimbusds.jose
Node.js: jose
.Net (C#): jose-jwt
Pseudo PHP example code
Webhook Messages
Webhook messages are POST
requests with JSON body:
LTI Outcomes
Annoto supports managing the LTI 1.3 Assignment and Grades via third party LTI 1.3 Tool. Webhook serving as a proxy medium.
Webhook messages JSON body:
Last updated