Creating webhooks
The first step to adding webhooks to your Indent integration is to build your own custom endpoint. Creating a webhook endpoint on your server is no different from creating any page on your website. With PHP, you might create a new .php file on your server; with a Ruby framework like Sinatra or Rails, you would add a new route.
We recommend considering a serverless or containerized option and a dedicated cloud account for additional levels of security isolation. Check out the Okta webhook as an example.
What does a webhook look like?
Webhooks should first verify the request is valid before handling any requests, then check if there's available logic to process the request and respond with a 200 HTTP status code. Here's an example in pseudocode of how Indent webhooks are structured:
async function(request: Request) {
if (verify(request) === false) {
throw new Error
}
if (match(request)) {
return await process(request)
}
return { statusCode: 200, body: '{}'}
}
Verifying the request
Indent signs all webhook requests it sends to your endpoints with a unique signature in the X-Indent-Signature
header. This signature lets you verify that requests are from Indent and not a third party. You can verify signatures with Indent's official library, or manually using your own solution.
Indent requests also include an X-Indent-Timestamp
header to provide an extra layer of certainty when it comes to the timeliness of requests, to mitigate time replay attacks.
Types of webhooks
There are two kinds of webhooks:
- Apply update — these webhooks receive Events like
access/grant
oraccess/revoke
to provision or deprovision access in a remote system. - Pull update — these webhooks receive a list of Resource Kinds like
myapp.v1.Admin
and respond with a list of API objects to update as Resources in your Space.
Apply update webhooks
Looking for a specific provider? Use one of our pre-built sample webhooks to get started.
Here is the starting point of a sample apply update webhook:
const { verify } = require('@indent/webhook')
exports['webhook'] = async function handle(req, res) {
const { body } = req
try {
await verify({
secret: process.env.INDENT_WEBHOOK_SECRET,
headers: req.headers,
body,
})
} catch (err) {
console.error('@indent/webhook.verify(): failed')
console.error(err)
return res.status(500).json({ error: { message: err.message } })
}
const { events } = body
console.log(`@indent/webhook: received ${events.length} events`)
console.log(JSON.stringify(events, null, 2))
await Promise.all(
events.map((auditEvent) => {
switch (auditEvent.event) {
case 'access/grant':
return grantPermission(auditEvent)
case 'access/revoke':
return revokePermission(auditEvent)
default:
return Promise.resolve()
}
})
)
return res.status(200).json({})
}
Pull update webhooks
Looking for a specific provider? Download one of our pre-built sample webhooks to get started.
Here is the starting point of a sample pull update webhook:
const { verify } = require('@indent/webhook')
exports['webhook'] = async function handle(req, res) {
const { body } = req
try {
await verify({
secret: process.env.INDENT_WEBHOOK_SECRET,
headers: req.headers,
body,
})
} catch (err) {
console.error('@indent/webhook.verify(): failed')
console.error(err)
return res.status(500).json({ error: { message: err.message } })
}
const { kinds } = body
console.log(`@indent/webhook: received kinds: ${kinds}`)
const resources = (
await Promise.all(kinds.map((kind) => loadResourcesForKind(kind)))
).flat()
return res.status(200).json({ resources })
}