Skip to content

Seeded webhook endpoints ignore a supplied secret, so a signature-verifying consumer cannot use the seed file #74

Description

@danielloader

Seeding a webhook endpoint always generates its signing secret and ignores a supplied one, while the HTTP route accepts one. src/workos/index.ts:

ws.webhookEndpoints.insert({
  object: 'webhook_endpoint',
  endpoint_url: endpointUrl,
  secret: randomBytes(32).toString('hex'),
  enabled: whConfig.enabled !== false,
  events: whConfig.events ?? [],
  description: null,
});

versus src/workos/routes/webhook-endpoints.ts:

const secret = (body.secret as string) ?? randomBytes(32).toString('hex');

So a consumer that verifies signatures cannot use the seed file for its endpoint at all: the secret it would need is generated after the emulator starts and is only discoverable by calling GET /webhook_endpoints. That leaves registering over the API as the only workable route, which is what we ended up doing, and it has a second cost with in-memory state: an endpoint registered after boot does not come back when the container restarts, so deliveries stop with nothing to explain why, whereas a seeded one would.

The fix looks like two lines:

-        secret: randomBytes(32).toString('hex'),
+        secret: whConfig.secret ?? randomBytes(32).toString('hex'),

plus secret?: string on WorkOSSeedWebhookEndpoint, and optionally a "must be a string if provided" check in config-validator.ts next to the existing events one. Unknown keys are not rejected today, so nothing else needs touching.

Is there a reason the webhook secret should differ from the other seeded credentials? apiKeys[].value is keyConfig.value ?? generated in the same function, and connectApplications[].client_secret is documented as optional and generated if omitted, both on the stated grounds that a service needs known credentials before anything interacts with the emulator. A signing secret seems like the same case, and it is the one seeded value a caller cannot discover without a follow-up request.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions