← Back to Blogus

Grant v1.5: Webhooks Close the Loop Back to Legacy IAM

7 min read
Ale Heredia
grant-platformopen-sourceidentityaccess-controlannouncement

In the last post we described how Grant is becoming a central place to see access across sources: an IAM data lake. Sync jobs pull identity data in from legacy systems, and from there teams work on users, roles, groups and permissions in the Grant UI. That covered one direction. The other direction was missing. Once someone changed something in Grant, nothing told the outside world, so the legacy system that still enforces access never found out.

Grant v1.5 fixes that. It is the biggest milestone since CDM Import & Export: a domain-event backbone with project webhooks and in-app notifications. Every meaningful change in Grant now produces a catalogued event, and those events can be delivered as signed HTTP calls to your own systems. For us, that turns a one-way migration pipe into a full round trip.

What is new in Grant v1.5

Under the hood, services publish domain events into a transactional outbox, written in the same database transaction as the data change and the audit log. Two independent consumers read from that outbox:

ConsumerWhat it does
WebhooksPOSTs a signed, redacted CloudEvents payload to the URLs a project subscribed
NotificationsResolves who should know, applies their preferences, and creates in-app notifications
%% width: desktop-60 mobile-100
flowchart TB
  svc[Service mutation] --> tx[Same DB transaction]
  tx --> data[Entity change]
  tx --> audit[Audit log]
  tx --> log[(event_log outbox)]
  log --> relay[Relay and sweep jobs]
  relay --> wh[Webhook dispatcher]
  relay --> ng[Notification generator]
  wh --> http[Signed HTTP POST]
  ng --> inbox[Notification center]

Because the event is written together with the change, there is no window where the data changed but the event got lost.

The release covers:

AreaWhat you get
Event catalogStable event types such as role.updated, user.role_assigned, group.permission_revoked or api_key.rotated, each with a category (security, iam, membership, integrations)
IAM coverageCreate, update and delete events for roles, groups, permissions and resources, plus assign and revoke events for users, roles, groups and permissions
Membership and securityOrganization invitations and members, project users, signing keys, MFA, sessions and password changes
Sync summariesproject_sync.completed and project_sync.failed when a CDM import or export job finishes
Webhooks UIProject → Webhooks: create subscriptions, pick event types, inspect deliveries, replay failed attempts, rotate the signing secret
Notification centerA bell with unread counts, an inbox, and per-category preferences in the dashboard

One detail matters a lot for anyone running sync jobs: CDM imports suppress entity-level events. A bulk import that touches hundreds of rows does not flood your webhooks or inboxes. Instead, Grant emits a single project_sync.completed (or project_sync.failed) summary when the job ends.

Full reference: Events, Webhooks & Notifications.

What a webhook looks like

A subscription is just an HTTPS URL, an optional description and the list of event types you care about. Each delivery is a JSON POST following CloudEvents 1.0, with a few Grant extensions that say where the change happened and who made it:

{
  "specversion": "1.0",
  "id": "…",
  "source": "https://your-grant-host",
  "type": "role.updated",
  "time": "2026-01-01T00:00:00.000Z",
  "subject": "role/…",
  "grantscope": { "tenant": "organizationProject", "id": "orgId:projectId" },
  "grantactor": { "userId": "…" },
  "grantcategory": "iam",
  "data": {
    "after": { "id": "…", "name": "Developer" },
    "delta": { "name": { "from": "Dev", "to": "Developer" } }
  }
}

Grant never puts secrets in event data, and webhook delivery redacts anything that looks like a secret or token as a second line of defense.

A few properties are worth knowing before you build on it:

  • Signed. Every delivery carries a Webhook-Signature header, an HMAC-SHA256 over the timestamp and body, using a signing secret that Grant shows once and lets you rotate. The docs explain how to verify it on your side.
  • At-least-once. Failed deliveries are retried on escalating delays, and any attempt can be replayed from the dashboard. Ordering isn't guaranteed, so receivers should be idempotent on the event id.
  • Safe by default. SSRF guards block private targets unless you allow them in configuration.

Notifications

Not every event is for a machine. The same outbox feeds the notification generator. It works out who should hear about each event (the affected user, owners, role holders), applies each person's preferences per category, and shows the result in the notification center. Security events stay on where policy requires it. If someone revokes your role or disables MFA on your account, you'll see it in the bell.

A real round trip: Alteos

I work at Alteos, and our use of Grant has grown release by release. CDM sync jobs let us port and map users from our legacy auth system into Grant, and since v1.4 that import runs repeatably. Once the data lands, teams make their access changes in the Grant UI.

That created an awkward asymmetry. Grant had become the most convenient place to make access changes, but the legacy system was still where many of those changes needed to take effect, and there was no way to send them back. Webhooks remove that gap, and we are now rolling the round trip out in production.

%% width: desktop-70 mobile-100
flowchart TB
  L[(Legacy auth system)]
  SJ[CDM sync jobs<br/>import / export]
  G[Grant<br/>IAM lake]
  OPS[Teams<br/>Grant UI]
  WH[Grant webhooks]
  FH[Amazon Data Firehose<br/>continuous change log]
  SF[AWS Step Functions<br/>map back to legacy]

  L -->|port and map users| SJ
  SJ --> G
  OPS -->|access changes| G
  G -->|domain events| WH
  WH --> FH
  FH --> SF
  SF -->|apply changes| L

The shape is simple:

  1. Collect. Grant webhooks feed every relevant change into Amazon Data Firehose, which gives us a continuous log of what happens in Grant.
  2. Batch. An Amazon EventBridge rule starts an AWS Step Functions workflow when the stream goes quiet for 10 seconds or the batch reaches 100 events. That way, a burst of edits is handled as one unit of work.
  3. Reconcile. AWS Lambda functions compare the changes with the current state, drop duplicates and resolve conflicts. A final step applies the result to the legacy system.
  4. Share. Each consolidated batch is posted to a Slack channel, saying who changed what and when.
%% width: desktop-60 mobile-100
flowchart TD
  FH[Amazon Data Firehose<br/>Grant change events] --> R{EventBridge rule}
  R -->|stream idle 10s| SF[AWS Step Functions]
  R -->|batch reaches 100 events| SF
  SF --> D[Lambda<br/>diff against current state]
  D --> DC[Lambda<br/>de-duplicate and resolve conflicts]
  DC --> A[Lambda<br/>apply to legacy system]
  A --> S[Slack<br/>who changed what and when]

Very little of this is Grant-specific code, and that is the point. Grant provides the pieces that make it work: an event for every access change, the actor and timestamp in each payload, signed delivery with retries, and quiet bulk imports. Because CDM imports suppress entity-level events, the data we bring in doesn't bounce straight back out as webhook calls. The rest is standard AWS building blocks.

The result closes the loop. Data flows from the legacy system into Grant through sync jobs, and changes made in Grant flow back through webhooks. The Slack channel turns access changes from something you find out about during an audit into something the team sees as it happens.

What comes next

v1.5 is the release where Grant stops being only a destination for identity data and starts talking back. Releases since then have kept polishing the experience. The webhook screens moved to a full-page create flow, and v1.6.2 fixed a bug that made the subscription detail page and secret rotation unusable. If you self-host, run v1.6.2 or later. Notification emails now use branded templates, and v1.13 gave the CLI commands for the whole REST API, webhook subscriptions included.

At Alteos, this round trip is now going into production. With it, Grant moves from a place where we see access to the place where we change it, with every change flowing back to the systems that still depend on it.

If you want to try it, create a project on demo.grantjs.org, add a webhook pointing at a request inspector, and change a role. Read the Events, Webhooks & Notifications guide, check the v1.5.0 release, and tell us on GitHub which events your integrations need next.

Comments

Comments are provided via Giscus (GitHub). Enable them in your cookie preferences to load the discussion widget.