HCMS Webhooks
Explains the connection of own business logic to write access to the Headless CMS with web technology.
Webhooks are a mechanism that allows developers to provide custom business logic to the Headless CMS that can modify entity data or reject operations on create, update and delete requests.
The business logic is invoked by calling a remote URL and can therefor be implemented in wide range of technologies.
Schema Configuration
Webhooks for the different operations are specified inside the schema in the top level object property cs:hook, which in turn contains a subset of the possible operations CREATE, UPDATE and DELETE as string properties containing the target URLs.
For example:
{
"cs:hook" : {
"CREATE" : "https://acme.com/validator"
},
"properties" : {
}
}
Webhook Protocol
The webhook URLs are called after the entity endpoints permission check is done but before the schema validation and actual persistence. All webhooks can accept the operation is it is or deny it, some operations allow the custom logic to modify the entity data before it is validated and persisted by the HCMS or even change the schema. Please note that in the later case permission check is repeated for the new schema.
CREATE | UPDATE | DELETE | |
---|---|---|---|
HTTP method | POST | PUT | DELETE |
Deny operation | Yes | Yes | Yes |
Modify entity | Yes | Yes | No |
Change schema | Yes | No | No |
Request
Each webhook URL must accept POST HTTP method with application/json body.
This JSON document contains following properties:
- schema: Schema name.
- operation: String identifier of the operation.
- endpoint: Full URL of the original request that caused the webhooks invocation.
- user-id: Entity ID of the user that executes this request. Only present when if such a user is available.
- user-domain and user-domain2: Asset domains of the user that executes this request. Only present when if such a user is available and it is represented by censhare asset.
- old: Contains the current data of the entity. This property is only present on UPDATE and DELETE operations.
- new: New data of the entity, as requested by the Headless CMS caller. This property is only present on CREATE and UPDATE operations.
- form-parts: Basic information about all parts of multipart request. Only present on CREATE and UPDATE operations invoked with multipart/form-data requests. The value is JSON object in which each property represents one named part of the request, the property name is the part name. Each part is described by a JSON object with following properties:
- headers: All headers of this part. Missing if this part has no headers.
- content-type: MIME type of this part as detected by HCMS or declared in header as fallback.
- filename: File name decoded from headers (Content-Disposition), missing not present.
For example:
{
"schema": "document",
"operation": "CREATE",
"endpoint": "http://localhost:9080/hcms/v2.1/entity/document",
"user-id": 67922,
"new": {
"owner": "http://localhost:9080/hcms/v2.1/entity/contact/67922",
"content": {"download": "formdata:file"},
"name": "test2.jpg"
},
"form-parts": {
"file": {
"headers": {
"Content-Disposition": ["form-data; name=\"file\"; filename=\"censhare-bildmarke.png\""],
"Content-Type": ["image/jpeg"]
},
"filename": "censhare-bildmarke.png",
"content-type": "image/jpeg"
},
"entity": {
"headers": {"Content-Disposition": ["form-data; name=\"entity\""]},
"content-type": "text/plain"
}
}
}
Response
The response must contain JSON document (object) with appropriate Content-Type: application/json header unless stated otherwise.
The possible HTTP status codes are:
- 200-299 "success": Proceed with operation.
- When the status 204 No Content is used no document must be returned.
- If modify entity is supported by the operation the property new can be present to supply modified entity data to be used by the HCMS instead of the original.
- If change schema is supported by the operation the property new-schema can be present to select a different schema to write the entity data to be used by the HCMS instead of the original.
- Additionally, response JSON can contain new-operation property to change nature of the operation. There are several limitations:
- Only UPDATE and DELETE are supported. CREATE can be used only if the request is already CREATE (i.e. no change).
- When changing DELETE to UPDATE, response actually has to contain new property; it is no longer optional, because there is no document supplied by the original request. Usually, the old document from request is used.
- Typical use is replacement of physical deletion by some kind of "deleted" flag.
- 401-403, 405-499 "client error": Operation is denied. Operation is aborted with HTTP status code 406 Not Acceptable. The Response body contains message "operation denied by hook" and the error message from the hook if there is any.
- 500-599 "server error", 404 Not Found or 400 Bad Request: Hook failed, the operation is aborted with HTTP status code 502 Bad Gateway and the response contains the full hook request and response.
- When the status code is 400 Bad Request and the body contains "error" property with JSON object value, HCMS returns the parsed error message.
Example of hook response that denies an operation (UPDATE):
{
"error": {
"new": "http://localhost:9080/hcms/v2.1/entity/contact/71049",
"old": "https://localhost:9080/hcms/v2.1/entity/contact/71049",
"property": "owner",
"message": "attempt to change \"owner\""
}
}
This cause HWCMS to return 406 error with this body:
{
"details": {
"new": "http://localhost:9080/hcms/v2.1/entity/contact/71049",
"old": "https://localhost:9080/hcms/v2.1/entity/contact/71049",
"property": "owner",
"message": "attempt to change \"owner\""
},
"error": "operation denied by hook"
}
Service Configuration
Additional configuration options are available in the Headless CMS OSGi service configuration XML.
These options can be configured on the optional top level element webhoooks.
- Attribute connection-timeout configures the HTTP client and contains maximum time in milliseconds spent initiating the HTTP connection. The default value is 500.
- Attribute timeout configures the HTTP client and contains maximum time of the whole HTTP request in milliseconds. The default value is 6000.
- Element base-url contains base URL of all hooks. If configured, the webhooks can be either absolute or relative (just the part, which is appended to the base).
- Element hmac enables MAC (message authentication signatures) for all requests and responses.
- Algorithm is the standard one defined by RFC 2104, with hashing either SHA-256 or SHA-512 (see also RFC 4231).
- Attribute secret contains the secret key (password) used to compute the signature.
- Optional attribute size allows algorithm selection, its value is either 256 or 512. The default is 256.
- All implementations of all hooks must use the same configuration, otherwise the request/response will fail.
Authentication
The transport security in terms of encryption can be covered by using HTTPS. Authorization is can be handled using message authentication code (MAC).
When enabled and configured, the special header x-signature-token is added to both request and response. In case of an request, it contains MAC of the request body treated as a UTF-8 string. In the case of a response, this header contains MAC of both request and response treated as two concatenated UTF-8 strings.
The algorithm is the a standard one defined by RFC 2104, with hashing either SHA-256 or SHA-512 (see also RFC 4231). Implementation is part of standard Java library (algorithms named HmacSHA256 and HmacSHA512) and node.js (algorithms named sha256 and sha512 used as argument of crypto.createHmac function). Result of HMAC is always encoded by base64 encoding.