calcom/cal.diy · critical · UnauthorizedException
Unauthorized
Error message
Unauthorized
What it means
A 401 UnauthorizedException (with NestJS default message 'Unauthorized') thrown by the BookingPbacGuard when request.user is null or undefined. The PBAC (Policy-Based Access Control) guard runs after the ApiAuthGuard, which is responsible for authenticating the request and populating request.user. If the guard fires without a prior successful authentication, it rejects with 401.
Source
Thrown at apps/api/v2/src/platform/bookings/2024-08-13/guards/booking-pbac.guard.ts:35
private bookingAccessService: BookingAccessService;
constructor(private readonly prismaReadService: PrismaReadService) {
this.bookingAccessService = new BookingAccessService(
this.prismaReadService.prisma
);
}
async canActivate(context: ExecutionContext): Promise<boolean> {
const request = context
.switchToHttp()
.getRequest<
Request & { user?: ApiAuthGuardUser; pbacAuthorizedRequest?: boolean }
>();
const user = request.user;
const bookingUid = request.params.bookingUid;
if (!user) {
throw new UnauthorizedException();
}
if (!bookingUid) {
throw new BadRequestException(
"BookingPbacGuard - bookingUid is required"
);
}
const hasAccess =
await this.bookingAccessService.doesUserIdHaveAccessToBooking({
userId: user.id,
bookingUid,
});
if (!hasAccess) {
throw new ForbiddenException(
`BookingPbacGuard - user with id=${user.id} does not have access to booking with uid=${bookingUid}`
);View on GitHub (pinned to 176037d0af)
Solutions
- Ensure the route has @UseGuards(ApiAuthGuard, BookingPbacGuard) in the correct order — ApiAuthGuard must run first to populate request.user.
- Verify the Authorization: Bearer header is present and valid — if ApiAuthGuard rejects, it should throw before PBAC runs.
- Check the ApiAuthGuard strategy (JWT or API key) for silent failures that return without throwing or setting user.
- If the guard ordering is correct, the issue is in the auth strategy — test authentication on a simpler ApiAuthGuard-only endpoint first.
Example fix
// before — missing ApiAuthGuard before PBAC
@UseGuards(BookingPbacGuard)
@Patch(':bookingUid')
async updateBooking(...) { ... }
// after — correct guard ordering
@UseGuards(ApiAuthGuard, BookingPbacGuard)
@Patch(':bookingUid')
async updateBooking(...) { ... } Defensive patterns
Strategy: validation
Validate before calling
// Ensure the token is valid before hitting a PBAC-protected route
async function validateToken(token) {
const res = await fetch('/v2/me', {
headers: { Authorization: `Bearer ${token}` }
});
return res.ok;
}
if (!(await validateToken(token))) {
throw new Error('Token is invalid or expired');
} Try / catch
try {
await api.updateBooking(bookingUid, updates);
} catch (err) {
if (err.statusCode === 401) {
// Token is invalid or missing — refresh or re-authenticate
const newToken = await refreshToken();
await api.updateBooking(bookingUid, updates); // retry
} else { throw err; }
} Prevention
- Always include a valid Authorization header when calling PBAC-protected routes.
- Ensure the ApiAuthGuard runs before BookingPbacGuard in the guard chain.
- Implement token refresh logic with automatic retry on 401.
- Test authentication on simpler endpoints before calling PBAC-protected routes.
When it happens
Trigger: Any route protected by BookingPbacGuard where the ApiAuthGuard did not set request.user — this typically means the route requires both @UseGuards(ApiAuthGuard, BookingPbacGuard) but the ApiAuthGuard was omitted, misconfigured, or the token validation failed silently.
Common situations: The route decorator is missing @UseGuards(ApiAuthGuard) before @UseGuards(BookingPbacGuard). The ApiAuthGuard strategy threw during authentication but the error was swallowed. The access token was rejected by the JWT strategy but a default/fallback strategy returned without setting user. A route was recently refactored and the guard ordering was broken.
Understand the failure class
- Authentication and authorization failures — expired tokens, bad credentials, and missing scopes.
Related errors
- ApiKeysService - This endpoint can only be accessed using an
- BookingPbacGuard - user with id=${user.id} does not have acc
- CustomThrottlerGuard - Invalid API Key
- ApiKeysService - No API key provided
- ApiKeysService - provided api key is not valid.
AI-assisted analysis of calcom/cal.diy@176037d0af (2026-08-12).
Data as JSON: /api/errors/9593f78edca89834.
Report an issue: GitHub.