Skip to main content

Creating webhooks

The first step to adding webhooks to your Indent webhook 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?#

When handling requests, webhooks should first verify the request is valid then check if there's available logic to process the request and respond with a 200 HTTP status code. At a high level, the pseudo-code looks something like this:

handle(request):
if verify(request) is False:
throw Error
if match(request):
return process(request)
return { statusCode: 200, body: '{}' }

Verifying the request#

Indent signs all webhook requests it sends to your endpoints by including a signature in each request’s X-Indent-Signature header. This allows you to verify that the requests were sent by Indent, not by a third party. You can verify signatures either using our official libraries, or manually using your own solution.

There is also an X-Indent-Timestamp header included in every request to provide an extra layer of certainty when it comes to the timeliness of requests, like preventing a time replay attack.

Kinds of webhooks#

There are currently only two kinds of webhooks:

  1. Change management — these webhooks receive Command Events like access/grant or access/revoke in order to provision or deprovision access in a remote system.
  2. Pull update — these webhooks receive a list of Resource Kinds like myapp.v1.Admin and respond with a list of API objects to bulk update as Resources.

Change management 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 change management 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 })
}