# WorkOS Webhooks

WorkOS is an enterprise-readiness platform (SSO, Directory Sync, AuthKit). It
delivers webhooks for Directory Sync, SSO connection, and User Management events
so your app can react to changes in enterprise identity providers.

## When to Use This Skill

* How do I receive WorkOS webhooks?
* How do I verify the WorkOS-Signature header?
* Why is my WorkOS webhook signature verification failing?
* How do I handle dsync.user.created or dsync.group.user_added events?
* How do I react to connection.activated, user.created, or session.created?

## Verification (core)

WorkOS signs each webhook with the `WorkOS-Signature` header, formatted
`t=<timestamp>, v1=<signature>`. The signature is an HMAC-SHA256 hex digest
over ``${timestamp}.${rawBody}`` using the endpoint signing secret. The
timestamp is in milliseconds; reject anything older than the tolerance
(default 180000 ms / 3 min) to prevent replay. Always use the raw request
body — don't `JSON.parse` first (the Node SDK re-`JSON.stringify`s objects,
which can change the bytes and break verification).

Node (official `@workos-inc/node` SDK — parses + verifies in one call):

```javascript
const { WorkOS } = require('@workos-inc/node');
const workos = new WorkOS(process.env.WORKOS_API_KEY);

const event = await workos.webhooks.constructEvent({
  payload: rawBody,                          // string/Buffer of the raw HTTP body
  sigHeader: req.headers['workos-signature'],
  secret: process.env.WORKOS_WEBHOOK_SECRET, // endpoint signing secret
});
// Throws SignatureVerificationException on tampering or a stale timestamp.
// event.event is the type string (e.g. 'dsync.user.created'); event.data is the object.

```

Manual (any language — for frameworks the SDK doesn't cover, e.g. FastAPI):

```python
ts, sig = parse_workos_signature(header)          # "t=..., v1=..."
if int(time.time() * 1000) - int(ts) > 180_000:   # milliseconds!
    reject()
expected = hmac.new(secret.encode(), f"{ts}.{raw_body}".encode(), hashlib.sha256).hexdigest()
hmac.compare_digest(expected, sig)                 # timing-safe

```

> For complete handlers with route wiring, event dispatch, and tests, see:
> 
> * [examples/express/](https://github.com/hookdeck/webhook-skills/tree/main/skills/workos-webhooks/examples/express/)
> * [examples/nextjs/](https://github.com/hookdeck/webhook-skills/tree/main/skills/workos-webhooks/examples/nextjs/)
> * [examples/fastapi/](https://github.com/hookdeck/webhook-skills/tree/main/skills/workos-webhooks/examples/fastapi/)

## Common Event Types

| Event | Triggered When |
| --- | --- |
| `dsync.user.created` | A user is added in a synced directory |
| `dsync.user.updated` | A directory user's attributes change |
| `dsync.group.user_added` | A user is added to a directory group |
| `connection.activated` | An SSO connection is activated |
| `user.created` | A User Management user is created |
| `session.created` | A user authenticates and a session starts |

> For the full event reference, see [WorkOS Events](https://workos.com/docs/events).

## Environment Variables

```bash
WORKOS_API_KEY=sk_test_xxxxx           # From WorkOS Dashboard → API Keys
WORKOS_WEBHOOK_SECRET=xxxxx            # Endpoint signing secret (per webhook endpoint)

```

## Local Development

```bash
# Start tunnel (no account needed)
npx hookdeck-cli listen 3000 workos --path /webhooks/workos

```

## Reference Materials

* [references/overview.md](https://github.com/hookdeck/webhook-skills/blob/main/skills/workos-webhooks/references/overview.md) - WorkOS webhook concepts and events
* [references/setup.md](https://github.com/hookdeck/webhook-skills/blob/main/skills/workos-webhooks/references/setup.md) - Dashboard configuration and signing secret
* [references/verification.md](https://github.com/hookdeck/webhook-skills/blob/main/skills/workos-webhooks/references/verification.md) - Signature verification details and gotchas