Per-Customer Access Control is essentially a way of ensuring the principle of least privilege (PoLP) in the context of employee access to customer data.
It's the practice of limiting access rights for users to the bare minimum permissions they need to perform their work.
Imagine a bank where employees can only access the accounts relevant to their role. A teller can manage cash transactions but can't authorize a loan - they simply don't have the "key" to that information.
The same principle applies to customer data in a digital environment. An employee in the sales team shouldn't have access to sensitive personal customer information that is unnecessary for them to perform sales tasks. Least privilege access reduces the risk of internal data breaches and prevents the misuse of privileged data.
More importantly, it helps maintain customer trust, as it ensures their data isn't exposed unnecessarily.
While it may seem like more administrative effort, the efficiency and safety paybacks can be substantial. Consider it the ultimate spring clean - getting rid of access that is no longer needed while being fundamentally aware of who has access to what data!
Here's how managing per-customer access with Indent works:
There's a few different options for how provisioning can work:
CustomerAccess_123
)assigned_customers=[123]
)We're going to use a custom webhook because it's the most flexible and we can use our existing production access control system rather than a side door.
The webhook will be called once access is granted. After the access time period expires, the webhook will be called again with the access/revoke
event and access will be cleaned up. That's it!
First, we'll upload our customers as Indent resources. We'll use the Indent API to create a new resource for each customer.
npm install @indent/api
Next, we'll need to list our customers from our database. We'll use the following query to list all customers:
select id, name, plan from customers;
We can write a script using @indent/api
to bulk upload them:
import { IndentAPI } from '@indent/api'import sql from './sql' // or some SQL clientconst indent = new IndentAPI({spaceName: process.env.INDENT_SPACE,apiToken: process.env.INDENT_API_TOKEN})async function upload() {const customers = await sql`select id, name, plan from customers;`await indent.resource.bulkUpdate({resources: customers.map(c => ({kind: 'customer',id: c.id,displayName: c.name,labels: { plan: c.plan }}))})}upload()
These resources will now show up in the Indent API:
> await indent.resource.list()[{ kind: 'customer', displayName: 'AcmeCorp', ... }, ...]
Next we'll need to handle when access is granted and revoked.
We'll need to create a webhook in Indent that will be called when a user is granted or revoked access to a customer.
Follow these steps to do that:
INDENT_WEBHOOK_SECRET
Next we'll need to create a webhook handler that will be called when a user is granted or revoked access to a customer.
We'll use the Indent Webhook SDK to verify the webhook signature and handle the event:
import { verify } from '@indent/webhook'import { Request, Response } from 'express'import { Event as AuditEvent } from '@indent/types' // for TypeScriptexport default async function(req: Request, res: Response) {try {const body = await json(req)await verify({secret: process.env.INDENT_WEBHOOK_SECRET,headers: req.headers,body: req.body})const { events } = bodyawait Promise.all(events.map((auditEvent: AuditEvent) => {let { actor, event, resources } = auditEventswitch (event) {case 'access/grant':return grantPermission(auditEvent)case 'access/revoke':return revokePermission(auditEvent)default:return Promise.resolve()}}))res.send(200, '{}')} catch (err) {res.send(200,JSON.stringify({ error: { message: err.message, stack: err.stack } }))}}async function grantPermission({ event, actor, resources }: AuditEvent) {// TODO: Grant permission/** {* "event": "access/grant",* "actor": { "email": "[email protected]" },* "resources": [ grantedUser, grantedResource ]* }*/}async function revokePermission({ event, actor, resources }: AuditEvent) {// TODO: Revoke permission/** {* "event": "access/revoke",* "actor": { "email": "[email protected]" },* "resources": [ revokedUser, revokedResource ]* }*/}
Once this webhook is deployed and configured in Indent, we can start granting and revoking access to customers.
You can also request approval on behalf of your team via the Indent API. This is useful if your team uses an internal admin panel or a tool system like Retool. Use the API to create petitions like this:
import { IndentAPI } from '@indent/api'const indent = new IndentAPI({spaceName: process.env.INDENT_SPACE,apiToken: process.env.INDENT_API_TOKEN})const petition = await indent.petition.create({resources: [{ kind: 'customer', id: '123' }]reason: 'to debug BUG-482',})// retry checking the petition until approved or timeoutawait indent.petition.waitFor({ petitionName: petition.name })
This is just the beginning. There's a lot more you can do with Indent to manage temporary access to customers:
Ready to start managing per-customer access control?
Check out Indent and get a demo →