From 12a4e2156e4db20f8cb5e6ab492c35844606cf1c Mon Sep 17 00:00:00 2001 From: "workos-tars[bot]" <269013284+workos-tars[bot]@users.noreply.github.com> Date: Tue, 10 Nov 2026 20:21:07 +0000 Subject: [PATCH] fix(user-management): Make membership organization names optional --- .../organization-membership.interface.ts | 6 +- src/webhooks/webhooks.spec.ts | 64 +++++++++++++++++++ 2 files changed, 67 insertions(+), 3 deletions(-) diff --git a/src/user-management/interfaces/organization-membership.interface.ts b/src/user-management/interfaces/organization-membership.interface.ts index 8aaac2b5c..0235e453d 100644 --- a/src/user-management/interfaces/organization-membership.interface.ts +++ b/src/user-management/interfaces/organization-membership.interface.ts @@ -16,8 +16,8 @@ export interface BaseOrganizationMembership { } export interface OrganizationMembership extends BaseOrganizationMembership { - /** The name of the organization which the user belongs to. */ - organizationName: string; + /** The organization's name, absent from event and action payloads. */ + organizationName?: string; /** The primary role assigned to the user within the organization. */ role: RoleResponse; roles?: RoleResponse[]; @@ -34,7 +34,7 @@ export interface BaseOrganizationMembershipResponse { object: 'organization_membership'; id: string; organization_id: string; - organization_name: string; + organization_name?: string; status: OrganizationMembershipStatus; user_id: string; directory_managed?: boolean; diff --git a/src/webhooks/webhooks.spec.ts b/src/webhooks/webhooks.spec.ts index ba3457286..cf0ad7556 100644 --- a/src/webhooks/webhooks.spec.ts +++ b/src/webhooks/webhooks.spec.ts @@ -17,6 +17,11 @@ import mockWebhook from './fixtures/webhook.json'; import { SignatureVerificationException } from '../common/exceptions'; // @oagen-ignore-start +import type { + OrganizationMembership, + OrganizationMembershipResponse, +} from '../user-management/interfaces'; + describe('Webhook signatures', () => { let payload: any; let secret: string; @@ -84,6 +89,65 @@ describe('Webhook signatures', () => { }); describe('constructEvent', () => { + describe.each([ + 'organization_membership.created', + 'organization_membership.updated', + 'organization_membership.deleted', + ])('%s', (event) => { + it.each([undefined, 'Example Organization'])( + 'accepts an organization name of %s', + async (organizationName) => { + const membership: OrganizationMembershipResponse = { + object: 'organization_membership', + id: 'om_123', + organization_id: 'org_123', + user_id: 'user_123', + status: 'active', + role: { slug: 'member' }, + created_at: '2023-11-16T21:32:25.235Z', + updated_at: '2023-11-16T21:32:25.235Z', + ...(organizationName && { organization_name: organizationName }), + }; + const expected: OrganizationMembership = { + object: 'organization_membership', + id: 'om_123', + organizationId: 'org_123', + userId: 'user_123', + status: 'active', + role: { slug: 'member' }, + directoryManaged: false, + customAttributes: {}, + createdAt: new Date(membership.created_at), + updatedAt: new Date(membership.updated_at), + ...(organizationName && { organizationName }), + }; + const rawBody = JSON.stringify({ + id: 'event_123', + event, + data: membership, + created_at: membership.created_at, + }); + const hash = crypto + .createHmac('sha256', secret) + .update(`${timestamp}.${rawBody}`) + .digest('hex'); + + const webhook = await workos.webhooks.constructEvent({ + payload: rawBody, + sigHeader: `t=${timestamp}, v1=${hash}`, + secret, + }); + + expect(webhook.event).toBe(event); + expect(webhook.data).toEqual(expected); + expect(webhook.data).toHaveProperty( + 'organizationName', + organizationName, + ); + }, + ); + }); + describe('with the correct payload, sig_header, and secret', () => { it('returns a webhook event', async () => { const sigHeader = `t=${timestamp}, v1=${signatureHash}`;