Webhook Format
JSON
This is the default format. We will send the payload exactly as it appears in the other pages of this documentation, which is a JSON object with a Content-Type of application/json
JWT (JSON Web Token)
This format is based on JSON Web Tokens and the Security Event Token (SET) standard. It provides a mechanism by which messages can be verified to ensure that only messages from Moneyhub can be accepted by your system. These messages will be encoded like a JWT and delivered with a Content-Type of application/jwt
Given the Payment Completed webhook, the JWT encoded version looks something like the following:
eyJraWQiOiJEOUpBTm1ZZlNHX2tidDJLUnBUS283UUNOSDJfUkstMGE3ODd5am0wN3p3IiwiYWxnIjoiUlMyNTYifQ.eyJpc3MiOiJodHRwczovL2lkZW50aXR5LWRldi5tb25leWh1Yi5jby51ayIsImF1ZCI6ImQ5ZGM5ZDVlLWQxOTAtNDM4Yy1iNjU4LWE0YmUzNzc5MTAwZCIsImp0aSI6ImM5ZDEzM2UwLWU3MDgtNDAyZC1hNmI3LWRjOGZmOWMyOWExYyIsInN1YiI6IjVmNzVhOWY5NDdmOWJkNzRkOTIxYTZjOSIsImV2ZW50cyI6eyJ1cm46Y29tOm1vbmV5aHViOmV2ZW50czpwYXltZW50LWNvbXBsZXRlZCI6eyJwYXltZW50SWQiOiJkYzk0NDZlZS1hZmMxLTRiNDctYmFiNS0yYjAxYzdkYTA5ZTMiLCJzdGF0dXMiOiJjb21wbGV0ZWQiLCJwYXltZW50U3VibWlzc2lvbklkIjoiMmJlOGNiZTUtZTEzOC00M2M1LWJjNTgtNzYwY2VmYTg5MjQ4Iiwic3VibWl0dGVkQXQiOiIyMDIwLTEwLTAxVDEwOjA1OjQ1LjM3NFoifX0sImlhdCI6MTYwMTU0Njc4MX0.Fld7AM3ywFUXaZYA8uFoGyiWalRhvM8V24a_n0pahYs8o2YGVk-5DCBVNwGGJZT0LMchXiVAo5QeRvauqCv6BsApyycQiGTpAbX0l9V97FANGotB9KRuwstXqZ9tNo9a70-oNJGu8CDsBO2i-mmdNGsCW5QQNGH3z_TtwBq8fX5zYhulc7HMvZr93kfO-zMZUHdeUmUBnqeig0IdCIM-67H1WzAYZ_s86ZMuZLEj5m_VyNas5rbEox4B8GW6aDzQO0YsBbp5jXzfkR0NVNUSip5Q1kTDtK24YbUz9Pt_pmsGof6a_3pSOw_oEAWnHH-C3a4zKQvUBklb9YeGVPv4OQ
Once decoded the payload would look like this:
{
"iss": "https://identity.moneyhub.co.uk",
"aud": "d9dc9d5e-d190-438c-b658-a4be3779100d",
"jti": "c9d133e0-e708-402d-a6b7-dc8ff9c29a1c",
"sub": "5f75a9f947f9bd74d921a6c9",
"events": {
"urn:com:moneyhub:events:payment-completed": {
"paymentId": "dc9446ee-afc1-4b47-bab5-2b01c7da09e3",
"status": "completed",
"paymentSubmissionId": "2be8cbe5-e138-43c5-bc58-760cefa89248",
"submittedAt": "2020-10-01T10:05:45.374Z"
}
},
"iat": 1601546781
}
You'll need to use a JWT library to decode and verify the messages
While you can decode the messages without verifying them, it's better to do both simultaneously. To verify the message, you'll need to retrieve our public signing key
Note: The key is subject to change over time without notice, so don't keep it as a static resource. For your security, the key returned does not display the algorithm. However, once validated, it possesses the capability to utilize it, ensuring a safe and secure experience.
Here is an example written in Node where we retrieve the public signing key to verify the webhook messages:
Packages used:
"got": "^10.5.0",
"node-jose": "^2.2.0",
const got = require("got")
const {JWK} = require("node-jose")
const getPublicMoneyhubKeyAsPEM = async () => {
try {
const {jwks_uri} = await got("https://identity.moneyhub.co.uk/oidc/.well-known/openid-configuration").json()
const jwks = await got(jwks_uri).json()
let signingKey = await JWK.asKeyStore(jwks)
signingKey = signingKey.get({use: "sig"})
console.log(signingKey.toPEM())
} catch (e) {
console.error(e)
}
}
getPublicMoneyhubKeyAsPEM()
This could then be extended to verify and decode the message like so:
const got = require("got")
const {JWS, JWK} = require("node-jose")
const decodeAndVerifyMessage = async (message) => {
try {
const {jwks_uri} = await got("https://identity.moneyhub.co.uk/oidc/.well-known/openid-configuration").json()
const jwks = await got(jwks_uri).json()
const signingKey = await JWK.asKeyStore(jwks)
const payload = await JWS.createVerify(signingKey).verify(message)
console.log(payload)
} catch (e) {
console.error("Failed to verify the message", e)
}
}
decodeAndVerifyMessage(message)
Updated 9 months ago