calcom/cal.diy · error · ForbiddenException
PermissionsGuard - no authentication provided. Provide eithe
Error message
PermissionsGuard - no authentication provided. Provide either authorization bearer token containing managed user access token or oAuth client id in 'x-cal-client-id' header.
What it means
ForbiddenException from PermissionsGuard when the request carries neither a Bearer token nor an x-cal-client-id header (and is also not a NextAuth token, API key, or third-party OAuth token — those bypass the guard at line 44). The guard only enforces permissions for platform OAuth clients/credentials; the missing-auth case is a 403, not 401, by design.
Source
Thrown at apps/api/v2/src/modules/auth/guards/permissions/permissions.guard.ts:48
if (!requiredPermissions?.length || !Object.keys(requiredPermissions)?.length) {
return true;
}
const request = context.switchToHttp().getRequest();
const bearerToken = request.get("Authorization")?.replace("Bearer ", "");
const nextAuthSecret = this.config.get("next.authSecret", { infer: true });
const nextAuthToken = await getToken({ req: request, secret: nextAuthSecret });
const oAuthClientId = request.params?.clientId || request.get(X_CAL_CLIENT_ID);
const apiKey = bearerToken && isApiKey(bearerToken, this.config.get("api.apiKeyPrefix") ?? "cal_");
const isThirdPartyBearerToken = bearerToken && this.getDecodedThirdPartyAccessToken(bearerToken);
// only check permissions for accessTokens attached to platform oAuth Client or platform oAuth credentials, not for next token or api key or third party oauth client
if (nextAuthToken || apiKey || isThirdPartyBearerToken) {
return true;
}
if (!bearerToken && !oAuthClientId) {
throw new ForbiddenException(
"PermissionsGuard - no authentication provided. Provide either authorization bearer token containing managed user access token or oAuth client id in 'x-cal-client-id' header."
);
}
const oAuthClient = bearerToken
? await this.getOAuthClientByAccessToken(bearerToken)
: await this.getOAuthClientById(oAuthClientId);
const hasRequiredPermissions = hasPermissions(oAuthClient.permissions, [...requiredPermissions]);
if (!hasRequiredPermissions) {
throw new ForbiddenException(
`PermissionsGuard - oAuth client with id=${
oAuthClient.id
} does not have the required permissions=${requiredPermissions
.map((permission) => this.oAuthClientsOutputService.transformOAuthClientPermission(permission))
.join(
", "View on GitHub (pinned to 176037d0af)
Solutions
- Send a valid Bearer token (managed-user access token) in the Authorization header, OR an x-cal-client-id header for a platform OAuth client.
- If using an API key (cal_…), confirm the prefix matches api.apiKeyPrefix (default 'cal_') so the apiKey short-circuit at line 41 fires.
- If using a NextAuth session, confirm NEXTAUTH_SECRET matches so getToken decodes a valid nextAuthToken.
- If using a third-party OAuth token, ensure getDecodedThirdPartyAccessToken recognizes it.
Example fix
// before curl https://api.example.com/v2/atoms -H 'cal-api-version: 2024-06-14' // after curl https://api.example.com/v2/atoms \ -H 'cal-api-version: 2024-06-14' \ -H 'Authorization: Bearer <managed-user-access-token>'
Defensive patterns
Strategy: validation
Validate before calling
const bearer = request.headers['authorization'];
const clientId = request.headers['x-cal-client-id'];
if (!bearer && !clientId) {
// client-side: tell user to provide credentials; do not send the request.
throw new Error('Missing Authorization header and x-cal-client-id');
} Type guard
function hasPlatformAuth(headers: Record<string,string|undefined>): boolean {
return Boolean(headers['authorization'] || headers['x-cal-client-id']);
} Prevention
- Always set either Authorization: Bearer <token> or x-cal-client-id on platform requests.
- Use the SDK's auth helpers so headers are attached consistently.
- Remember API keys (cal_…) and NextAuth tokens bypass PermissionsGuard — use those if permissions aren't required.
When it happens
Trigger: Calling any platform endpoint guarded by PermissionsGuard with no Authorization header AND no x-cal-client-id header (and no clientId route param). Earlier short-circuits return true for NextAuth tokens, cal_ API keys, and recognized third-party bearer tokens.
Common situations: Client forgot the Authorization header; using x-cal-client-id but misspelled the header; curl/Postman request built without auth; SDK not configured with the OAuth client id; dev environment missing the platform client entirely.
Understand the failure class
- Authentication and authorization failures — expired tokens, bad credentials, and missing scopes.
Related errors
- PermissionsGuard - oAuth client with id=${oAuthClient.id} do
- PermissionsGuard - no oAuth client found for access token=${
- PermissionsGuard - no oAuth client found for client id=${id}
- EventTypeOwnershipGuard - No user associated with the reques
- RolesGuard - user with id=${user.id} does not have the minim
AI-assisted analysis of calcom/cal.diy@176037d0af (2026-08-12).
Data as JSON: /api/errors/8b538039dd469e3f.
Report an issue: GitHub.