{"record":{"id":"9593f78edca89834","repo":"calcom/cal.diy","slug":"unauthorized","errorCode":null,"errorMessage":"Unauthorized","messagePattern":"Unauthorized","errorType":"http","errorClass":"UnauthorizedException","httpStatus":401,"severity":"critical","filePath":"apps/api/v2/src/platform/bookings/2024-08-13/guards/booking-pbac.guard.ts","lineNumber":35,"sourceCode":"  private bookingAccessService: BookingAccessService;\n\n  constructor(private readonly prismaReadService: PrismaReadService) {\n    this.bookingAccessService = new BookingAccessService(\n      this.prismaReadService.prisma\n    );\n  }\n\n  async canActivate(context: ExecutionContext): Promise<boolean> {\n    const request = context\n      .switchToHttp()\n      .getRequest<\n        Request & { user?: ApiAuthGuardUser; pbacAuthorizedRequest?: boolean }\n      >();\n    const user = request.user;\n    const bookingUid = request.params.bookingUid;\n\n    if (!user) {\n      throw new UnauthorizedException();\n    }\n\n    if (!bookingUid) {\n      throw new BadRequestException(\n        \"BookingPbacGuard - bookingUid is required\"\n      );\n    }\n\n    const hasAccess =\n      await this.bookingAccessService.doesUserIdHaveAccessToBooking({\n        userId: user.id,\n        bookingUid,\n      });\n\n    if (!hasAccess) {\n      throw new ForbiddenException(\n        `BookingPbacGuard - user with id=${user.id} does not have access to booking with uid=${bookingUid}`\n      );","sourceCodeStart":17,"sourceCodeEnd":53,"githubUrl":"https://github.com/calcom/cal.diy/blob/176037d0afbe572f870a3c702985e7cd83fe6c0c/apps/api/v2/src/platform/bookings/2024-08-13/guards/booking-pbac.guard.ts#L17-L53","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","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."],"exampleFix":"// before — missing ApiAuthGuard before PBAC\n@UseGuards(BookingPbacGuard)\n@Patch(':bookingUid')\nasync updateBooking(...) { ... }\n\n// after — correct guard ordering\n@UseGuards(ApiAuthGuard, BookingPbacGuard)\n@Patch(':bookingUid')\nasync updateBooking(...) { ... }","handlingStrategy":"validation","validationCode":"// Ensure the token is valid before hitting a PBAC-protected route\nasync function validateToken(token) {\n  const res = await fetch('/v2/me', {\n    headers: { Authorization: `Bearer ${token}` }\n  });\n  return res.ok;\n}\n\nif (!(await validateToken(token))) {\n  throw new Error('Token is invalid or expired');\n}","typeGuard":null,"tryCatchPattern":"try {\n  await api.updateBooking(bookingUid, updates);\n} catch (err) {\n  if (err.statusCode === 401) {\n    // Token is invalid or missing — refresh or re-authenticate\n    const newToken = await refreshToken();\n    await api.updateBooking(bookingUid, updates); // retry\n  } else { throw err; }\n}","preventionTips":["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."],"tags":["authentication","guard","nestjs","pbac","unauthorized","authorization"],"backgroundTag":null,"analyzedSha":"176037d0afbe572f870a3c702985e7cd83fe6c0c","analyzedAt":"2026-08-12T19:12:41.464Z","schemaVersion":2},"datasetVersion":"2026-08-12T23:17:12.415Z"}