calcom/cal.diy · error · UnauthorizedException

These credentials do not belong to you

Error message

These credentials do not belong to you

What it means

Thrown by CalendarsService.getUniqCalendarCredentials (calendars.service.ts:151) as UnauthorizedException (HTTP 401) when getUserCredentialsByIds(userId, uniqueCredentialIds) returns fewer rows than the number of unique credentialIds requested. At least one credentialId in calendarsToLoad is absent or belongs to another user (the query filters by userId).

Source

Thrown at apps/api/v2/src/platform/calendars/services/calendars.service.ts:151

        const busyTimeEnd = DateTime.fromJSDate(new Date(busyTime.end)).setZone(timezone);
        const busyTimeStartDate = busyTimeStart.toJSDate();
        const busyTimeEndDate = busyTimeEnd.toJSDate();
        return {
          ...busyTime,
          start: busyTimeStartDate,
          end: busyTimeEndDate,
        };
      }
    );
    return calendarBusyTimesConverted;
  }

  async getUniqCalendarCredentials(calendarsToLoad: Calendar[], userId: User["id"]) {
    const uniqueCredentialIds = Array.from(new Set(calendarsToLoad.map((item) => item.credentialId)));
    const credentials = await this.credentialsRepository.getUserCredentialsByIds(userId, uniqueCredentialIds);

    if (credentials.length !== uniqueCredentialIds.length) {
      throw new UnauthorizedException("These credentials do not belong to you");
    }

    return credentials;
  }

  async getCalendarsWithCredentials(
    credentials: CredentialsWithUserEmail,
    calendarsToLoad: Calendar[],
    userId: User["id"]
  ) {
    const composedSelectedCalendars = calendarsToLoad.map((calendar) => {
      const credential = credentials.find((item) => item.id === calendar.credentialId);
      if (!credential) {
        throw new UnauthorizedException("These credentials do not belong to you");
      }
      return {
        ...calendar,
        userId,

View on GitHub (pinned to 176037d0af)

Solutions

  1. Only pass credentialIds returned by GET /v2/calendars for the currently authenticated user.
  2. Filter calendarsToLoad client-side to ids present in the user's connectedCalendars before calling busy-times.
  3. Treat a 401 here as a security signal — do not silently retry with the same ids.

Example fix

// before: passing whatever ids the client holds
await api.get('/v2/calendars/busy-times', { params: { calendarsToLoad } }); // 401

// after: intersect with the user's own credential ids
const { data } = await api.get('/v2/calendars');
const owned = new Set(data.connectedCalendars.map(c => c.credentialId));
const safe = calendarsToLoad.filter(c => owned.has(c.credentialId));
await api.get('/v2/calendars/busy-times', { params: { calendarsToLoad: safe } });
Defensive patterns

Strategy: validation

Validate before calling

// Intersect requested ids with the user's own credentials before busy-times
const { data } = await api.get('/v2/calendars');
const owned = new Set(data.connectedCalendars.map(c => c.credentialId));
const safe = calendarsToLoad.filter(c => owned.has(c.credentialId));
if (safe.length !== calendarsToLoad.length) {
  throw new Error('Some credentialIds are not owned by this user');
}
await api.get('/v2/calendars/busy-times', { params: { ...params, calendarsToLoad: safe } });

Type guard

function allOwned(requestedIds, ownedIds) {
  return requestedIds.every((id) => ownedIds.has(id));
}

Try / catch

try {
  await api.get('/v2/calendars/busy-times', { params });
} catch (e) {
  if (e.response?.status === 401 && /do not belong/i.test(e.response?.data?.message)) {
    // security signal — do NOT retry with the same ids; refresh ownership
    await refreshCalendarList();
    throw new AuthorizationError('credentialId ownership mismatch');
  }
  throw e;
}

Prevention

When it happens

Trigger: GET /v2/calendars/busy-times with a calendarsToLoad[].credentialId belonging to another user; a deleted credential id; a fabricated/guessed id; stale id cached client-side after re-connecting a different account.

Common situations: Client caches credentialIds across account switches; multi-tenant mix-up; frontend retained an id after the user re-authenticated as someone else.

Related errors


AI-assisted analysis of calcom/cal.diy@176037d0af (2026-08-12). Data as JSON: /api/errors/0589bd2832e3f797. Report an issue: GitHub.