Skip to main content

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:

  1. Change management — these webhooks receive Command Events like access/grant or access/revoke 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 update as Resources in your Space.

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 })
}