{"record":{"id":"adf330c2dc6eb6e4","repo":"calcom/cal.diy","slug":"oauthclientguard-no-oauth-client-associated-with","errorCode":null,"errorMessage":"OAuthClientGuard - No OAuth client associated with the request.","messagePattern":"OAuthClientGuard - No OAuth client associated with the request\\.","errorType":"exception","errorClass":"ForbiddenException","httpStatus":403,"severity":"critical","filePath":"apps/api/v2/src/modules/oauth-clients/guards/oauth-client-guard.ts","lineNumber":24,"sourceCode":"  Injectable,\n  CanActivate,\n  ExecutionContext,\n  ForbiddenException,\n  NotFoundException,\n} from \"@nestjs/common\";\n\n@Injectable()\nexport class OAuthClientGuard implements CanActivate {\n  constructor(private oAuthClientRepository: OAuthClientRepository, private usersService: UsersService) {}\n\n  async canActivate(context: ExecutionContext): Promise<boolean> {\n    const request = context.switchToHttp().getRequest<ApiAuthGuardRequest>();\n    const organizationId = this.getOrganizationId(context);\n    const user: ApiAuthGuardUser = request.user;\n    const oAuthClientId = request.params.clientId;\n\n    if (!oAuthClientId) {\n      throw new ForbiddenException(\"OAuthClientGuard - No OAuth client associated with the request.\");\n    }\n\n    if (!user || !organizationId) {\n      throw new ForbiddenException(\"OAuthClientGuard - No organization associated with the user.\");\n    }\n\n    const oAuthClient = await this.oAuthClientRepository.getOAuthClient(oAuthClientId);\n\n    if (!oAuthClient) {\n      throw new NotFoundException(\"OAuthClientGuard - OAuth client not found.\");\n    }\n\n    const allowed = Boolean(user.isSystemAdmin || oAuthClient.organizationId === organizationId);\n    if (!allowed) {\n      throw new ForbiddenException(\n        `OAuthClientGuard - forbidden. oAuth client with id=${oAuthClientId} does not belong to the organization with id=${organizationId}.`\n      );\n    }","sourceCodeStart":6,"sourceCodeEnd":42,"githubUrl":"https://github.com/calcom/cal.diy/blob/176037d0afbe572f870a3c702985e7cd83fe6c0c/apps/api/v2/src/modules/oauth-clients/guards/oauth-client-guard.ts#L6-L42","documentation":"Thrown by the OAuthClientGuard (a NestJS CanActivate guard applied to OAuth-client-scoped routes) when request.params.clientId is falsy. The guard reads the client id from the route param; if the route was mounted without a :clientId segment, or the param is somehow absent, it rejects with ForbiddenException (HTTP 403). This is a routing/configuration defect, not a user input error.","triggerScenarios":"A controller method decorated with @UseGuards(OAuthClientGuard) is mounted on a route that has no :clientId parameter, or the request reaches it via a path that didn't populate the param. Reproducible only by misconfigured routing — a correctly mounted route always has the param.","commonSituations":"Refactoring a controller and forgetting to keep :clientId in the route path; mounting the controller under a prefix that already consumed the param; a test that invokes the handler directly without a mocked params object.","solutions":["Ensure every route guarded by OAuthClientGuard includes :clientId in its path, e.g. @Controller(':clientId') at the class level or :clientId in each @Post/@Get path.","In unit tests, mock request.params = { clientId: '<id>' } before invoking the guard.","Verify the controller's @Controller() prefix and method path together contain :clientId.","Grep the module routing to confirm no guard-protected route lacks the param."],"exampleFix":"// before\n@Controller('oauth-clients')\n@UseGuards(OAuthClientGuard)\nexport class OAuthClientController {\n  @Get('events')           // no :clientId — guard throws\n  getEvents() { ... }\n}\n\n// after\n@Controller('oauth-clients/:clientId')\n@UseGuards(OAuthClientGuard)\nexport class OAuthClientController {\n  @Get('events')           // :clientId now in scope\n  getEvents() { ... }\n}","handlingStrategy":"validation","validationCode":"// Server-side: assert the route exposes :clientId before mounting the guard\nfunction assertRouteHasClientId(path: string) {\n  if (!/:clientId(\\b|\\?|$|\\()/.test(path)) {\n    throw new Error(`Route '${path}' uses OAuthClientGuard but has no :clientId param`);\n  }\n}","typeGuard":"function requestHasClientId(req: { params?: Record<string, unknown> }): req is { params: { clientId: string } } {\n  return typeof req.params?.clientId === 'string' && (req.params as any).clientId.length > 0;\n}","tryCatchPattern":"// Guard-level: throw early and descriptive — callers cannot recover from a routing bug.\n// Fix the route definition rather than catching at runtime.","preventionTips":["Keep :clientId in the @Controller prefix for every OAuthClientGuard-protected controller.","Add an integration test that hits each guarded route.","In unit tests, mock request.params.clientId explicitly."],"tags":["nestjs","guard","routing","oauth","configuration","server-bug"],"backgroundTag":null,"analyzedSha":"176037d0afbe572f870a3c702985e7cd83fe6c0c","analyzedAt":"2026-08-12T19:12:41.464Z","schemaVersion":2},"datasetVersion":"2026-08-12T23:17:12.415Z"}