Webhooks are one way that ContentGrid applications can send automated messages or information to external systems. They are almost always faster than polling, and require less work on your end.
Each mutating operation on an resource is handled individually and is asynchronously, but almost immediately delivered to the configured webhook endpoint.
A ContentGrid Webhook
is always attached to a ContentGrid entity and selected change triggers
is delivered to a configured HTTP endpoint
is delivered as a HTTP POST message with a body payload and specific ContentGrid HTTP headers
First, go to the Webhooks modeler:
To create our first Webhook, we first have to click on Create Webhook:
When clicking the "Create Webhook" button you will see the configuration options for creating a new Webhook:
First, you will have to give a satisfying Webhook name (or description).
Then you have to choose for which entity this Webhook will be applied
After the entity selection, select the notifications triggers, where the options are
create (whenever the selected entity type is created)
update (when each existing entity is being updated)
content (when a document content has been changed)
delete (when the enetity selected has been deleted)
As a last step, you have to provide the Webhook URL to be invoked by your ContentGrid application
After clicking save, the Webhook is saved and is listed in the overview but will only be available to your ContentGrid runtime application once you create a new Release
You can add more Webhooks with the "Create Webhook" button.
A Webhook endpoint has some specific constraints and must respect the following implementation details:
it has to support the HTTP POST method
should accept a JSON body and application/json Content-Type
can use our ContentGrid HTTP headers in order to validate that the delivered message is coming from our platform
User-Agent value is ContentGrid-Slingshot/APP_VERSION
ContentGrid-Application-Id contains the application id
ContentGrid-Deployment-Id contains the deployment id
ContentGrid-Signature provides a JWT signed by the our platform that should be used in order that the message is actually sent by the ContentGrid platform
ContentGrid signs JWTs using asymmetric encryption (RS256), and publishes the public signing keys in a JWKS (JSON Web Key Set).
The signing keys are rotated on a regular basis.
We discourage doing manual JWT validation since it might be easy to improperly implement and miss some important details that will lead to serious security vulnerabilities. Most JWT libraries take care of JWT validation for you.
We also highly recommend to use a JWK library for the programming language of your choice.
One of the benefits of JSON Web Token (JWT) is that you can validate a token using an easy cryptographic operation.
A JSON Web Key (JWK) is a JSON data structure that represents a cryptographic key. JWKs are a set of keys shared between different services and are used to verify the JWT token from the authorization server.
You should only be validating the received JWT against ContentGrid Json Web Key (JWK) URL which is ${CONTENTGRID_URL}/.well-known/jwks.json
We use JWKS to expose the public keys used by the ContentGrid platform to all the clients required to validate signatures.
For more information you can check the JWK RFC
The example of a JWKS is something that looks like this:
{ "keys": [ { "use": "sig", "kty": "RSA", "kid": "UVelusmvyM2xScEu0F_xSNlhelC5jZTD77R_3mmOZXs", "alg": "RS256", "n": "...yjXzcFpbMJB1fIFam9lQBeXWbTqzJwbuFbspHMsRowa8FaPw44l2C9Q42J3AdQD8CcN...", "e": "AQAB" }, { ... } ] }
In the above example some important fields are
e: is the exponent for a standard pem
n: is the moduluos for a standard pem
alg: the signing algorithm.
kid: a unique id for every key in the set.
{ "kid": "UVelusmvyM2xScEu0F_xSNlhelC5jZTD77R_3mmOZXs", "alg": "RS256" }.{ "aud": "https://webhooks-demo.rtp-scw-sandbox.contentgrid.cloud/broker-process", "exp": 1679044765, "iat": 1679044465, "jti": "df475d5a-fc0e-4fca-a03a-c279e86fe9ed" }.[Signature]
kid: is Identifier of the static key used to sign the JWT
alg: Algorithm used to sign the key
aud: Recipients that the JWT is intended for (the CG Application URL)
iat: The issuing time of the token in seconds
exp: The expiration time of the token in seconds
jti: Unique identifier of the token
Here is a Java exmaple of how to validate a JWT using JWKs with Nimbus JOSE + JWT
To validate the token, first, you need to get the JSON web key set from the JWKs endpoint. The token will be received as JSON in the validation endpoint in the body.
ResourceRetriever jwkSetRetriever = new DefaultResourceRetriever(); JWKSource<SecurityContext> jwkSource = new RemoteJWKSet<>(URI.create("${CONTENTGRID_URL}/.well-known/jwks.json").toURL(), jwkSetRetriever); JWSKeySelector<SecurityContext> jwsKeySelector = JWSAlgorithmFamilyJWSKeySelector.fromJWKSource(jwkSource);
Additional validation for token claims
ConfigurableJWTProcessor<SecurityContext> jwtProcessor = new DefaultJWTProcessor<>(); jwtProcessor.setJWSKeySelector(jwsKeySelector); jwtProcessor.setJWTClaimsSetVerifier((claims, context) -> { final Date now = new Date(); final Date exp = claims.getExpirationTime(); if (exp != null) { if (now.after(exp)) { throw new BadJWTException("expired"); } } });
and the JWT validation
SignedJWT signedJWT = SignedJWT.parse(THE_JWT); jwtProcessor.process(signedJWT, null);
This short guide provides the basic steps required to locally verify an access or ID token signed by ContentGrid. It uses packages from Nimbus JOSE + JWT for key parsing and token validation, but the general principles should apply to any JWT validation library.