Skip to content

Instantly share code, notes, and snippets.

@gunndabad
Created January 13, 2025 15:55
Show Gist options
  • Select an option

  • Save gunndabad/8c6f0fc764535ebb5b78ce406838103a to your computer and use it in GitHub Desktop.

Select an option

Save gunndabad/8c6f0fc764535ebb5b78ce406838103a to your computer and use it in GitHub Desktop.
TRS webhook verifier
import express from "express";
import { verify } from "@ltonetwork/http-message-signatures";
import ec from "js-crypto-ec";
const app = express();
const port = 3000;
const trsJwksEndpoint =
"https://preprod.teacher-qualifications-api.education.gov.uk/webhook-jwks";
async function getTrsKeys() {
const res = await fetch(trsJwksEndpoint);
const jwks = await res.json();
const keys = {};
for (let key of jwks["keys"]) {
keys[key["kid"]] = key;
}
return keys;
}
const keys = await getTrsKeys();
app.set("trust proxy", "loopback");
app.listen(port, () => {
console.log(`Listening on port ${port}`);
});
app.post("/webhook", async (req, res) => {
try {
//console.log(req.headers);
// @target-uri is derived from req.url - ensure it's the full URL
req.url = req.protocol + "://" + req.get("host") + req.originalUrl;
//console.log(req.url);
// TODO Verify Content-Digest header
const verified = await verifySignature(req);
console.log("Verification succeeded");
res.status(204);
} catch (err) {
console.error("Verification failed: ", err.message);
res.status(401);
}
});
async function verifySignature(req) {
await verify(req, async (data, signature, params) => {
const key = keys[params["keyid"]];
const valid = await ec.verify(data, signature, key, "SHA-384", "raw");
if (!valid) throw new Error("Invalid signature");
return {};
});
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment