calcom/cal.diy · error · ForbiddenException
IsUserWebhookGuard - user with id=(${user.id}) is not the ow
Error message
IsUserWebhookGuard - user with id=(${user.id}) is not the owner of webhook with id=(${webhookId}) What it means
IsUserWebhookGuard fetched the webhook by id and found that webhook.userId does not equal the authenticated user's id, and the user is not a system admin. The guard enforces per-user ownership of webhooks; only the owner or a system admin may proceed. It throws ForbiddenException (HTTP 403).
Source
Thrown at apps/api/v2/src/modules/webhooks/guards/is-user-webhook-guard.ts:28
constructor(private readonly webhooksService: WebhooksService) {}
async canActivate(context: ExecutionContext): Promise<boolean> {
const request = context.switchToHttp().getRequest<Request & { webhook: Webhook }>();
const user = request.user as ApiAuthGuardUser;
const webhookId = request.params.webhookId;
if (!user) {
throw new ForbiddenException("IsUserWebhookGuard - No user associated with the request.");
}
if (!webhookId) {
throw new ForbiddenException("IsUserWebhookGuard - No webhook id found in request params.");
}
const webhook = await this.webhooksService.getWebhookById(webhookId);
if (webhook.userId !== user.id && !user.isSystemAdmin) {
throw new ForbiddenException(
`IsUserWebhookGuard - user with id=(${user.id}) is not the owner of webhook with id=(${webhookId})`
);
}
request.webhook = webhook;
return true;
}
}
View on GitHub (pinned to 176037d0af)
Solutions
- Authenticate as the user who owns the webhook (the user whose id equals webhook.userId).
- If legitimate admin access is required, perform the call with a system-admin account.
- Verify the webhookId belongs to the current user via a list-my-webhooks call before operating on it.
- Audit the client's session/token handling to ensure the correct user context is sent.
Example fix
// before
await api.delete(`/webhooks/${webhookId}`); // wrong session
// after
const mine = await api.get('/webhooks');
if (!mine.find(w => w.id === webhookId)) throw new ForbiddenError('not owner');
await api.delete(`/webhooks/${webhookId}`); Defensive patterns
Strategy: validation
Validate before calling
async function ensureOwnsWebhook(api, user, webhookId) {
const mine = await api.listMyWebhooks();
if (!mine.find(w => w.id === webhookId) && !user.isSystemAdmin) {
throw new ForbiddenError(`user ${user.id} does not own ${webhookId}`);
}
} Type guard
const isWebhookOwner = (webhook: { userId: number }, user: { id: number; isSystemAdmin?: boolean }): boolean =>
webhook.userId === user.id || user.isSystemAdmin === true; Try / catch
try { await api.delete(`/webhooks/${id}`); }
catch (e) {
if (e.status === 403 && /not the owner/.test(e.message)) { /* use owner session or admin */ }
else throw e;
} Prevention
- Operate on webhooks only from the session of the user who owns them.
- Maintain a mapping of webhookId -> ownerId in the client to detect mismatches early.
- Reserve system-admin usage for explicit admin tooling.
When it happens
Trigger: An authenticated user calls a webhook endpoint (GET/PATCH/DELETE) for a webhook owned by a different user, while not having isSystemAdmin=true. The guard compares webhook.userId === user.id after loading the webhook.
Common situations: Cross-tenant access bug in the client (wrong user session reused); sharing a webhook id between team members who are not admins; a token from user A used to operate on user B's webhook; stale cached id.
Related errors
- Event type with id ${eventTypeId} not found
- IsUserWebhookGuard - No webhook id found in request params.
- User with ID ${userId} is not part of this OAuth client.
- Unauthorized
- BookingPbacGuard - user with id=${user.id} does not have acc
AI-assisted analysis of calcom/cal.diy@176037d0af (2026-08-12).
Data as JSON: /api/errors/16cd47b0f6a64457.
Report an issue: GitHub.