Skip to content

Commit e3da9f4

Browse files
jaredpiedtbrkalow
andauthored
feat(backend): Add event_attributes to Webhook type (#6162)
Co-authored-by: Bryce Kalow <bryce@clerk.dev>
1 parent 32a4952 commit e3da9f4

4 files changed

Lines changed: 45 additions & 1 deletion

File tree

.changeset/sixty-regions-camp.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
'@clerk/backend': patch
3+
---
4+
5+
Add `event_attributes` to the `Webhook` type.

packages/backend/src/__tests__/webhooks.test.ts

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -217,4 +217,35 @@ describe('verifyWebhook', () => {
217217
// All should be treated as missing
218218
await expect(verifyWebhook(mockRequest)).rejects.toThrow('svix-id, svix-timestamp, svix-signature');
219219
});
220+
221+
it('should parse event_attributes', async () => {
222+
const clerkPayload = JSON.stringify({
223+
type: 'user.created',
224+
data: { id: 'user_123', email: 'test@example.com' },
225+
event_attributes: {
226+
http_request: {
227+
client_ip: '127.0.0.1',
228+
user_agent: 'Mozilla/5.0 (Test)',
229+
},
230+
},
231+
});
232+
const svixId = 'msg_123';
233+
const svixTimestamp = (Date.now() / 1000).toString();
234+
const validSignature = createValidSignature(svixId, svixTimestamp, clerkPayload);
235+
236+
const mockRequest = new Request('https://clerk.com/webhooks', {
237+
method: 'POST',
238+
body: clerkPayload,
239+
headers: new Headers({
240+
'svix-id': svixId,
241+
'svix-timestamp': svixTimestamp,
242+
'svix-signature': validSignature,
243+
}),
244+
});
245+
246+
const result = await verifyWebhook(mockRequest, { signingSecret: mockSecret });
247+
expect(result).toHaveProperty('type', 'user.created');
248+
expect(result).toHaveProperty('event_attributes.http_request.client_ip', '127.0.0.1');
249+
expect(result).toHaveProperty('event_attributes.http_request.user_agent', 'Mozilla/5.0 (Test)');
250+
});
220251
});

packages/backend/src/api/resources/Webhooks.ts

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,14 @@ import type {
1313
WaitlistEntryJSON,
1414
} from './JSON';
1515

16-
type Webhook<EvtType, Data> = { type: EvtType; object: 'event'; data: Data };
16+
type WebhookEventAttributes = {
17+
http_request: {
18+
client_ip: string;
19+
user_agent: string;
20+
};
21+
};
22+
23+
type Webhook<EvtType, Data> = { type: EvtType; object: 'event'; data: Data; event_attributes: WebhookEventAttributes };
1724

1825
export type UserWebhookEvent =
1926
| Webhook<'user.created' | 'user.updated', UserJSON>

packages/backend/src/webhooks.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -129,6 +129,7 @@ export async function verifyWebhook(request: Request, options: VerifyWebhookOpti
129129
type: payload.type,
130130
object: 'event',
131131
data: payload.data,
132+
event_attributes: payload.event_attributes,
132133
} as WebhookEvent;
133134
} catch (e) {
134135
return errorThrower.throw(`Unable to verify incoming webhook: ${e instanceof Error ? e.message : 'Unknown error'}`);

0 commit comments

Comments
 (0)