{"record":{"id":"47a556a702ac794b","repo":"calcom/cal.diy","slug":"reason","errorCode":null,"errorMessage":"${reason}","messagePattern":"\\$\\{reason\\}","errorType":"http","errorClass":"OAuth2HttpException","httpStatus":null,"severity":"error","filePath":"apps/api/v2/src/modules/auth/oauth2/services/oauth2-error.service.ts","lineNumber":26,"sourceCode":"  \"client_not_found\",\n  \"client_not_approved\",\n  \"client_rejected\",\n  \"redirect_uri_mismatch\",\n]);\n\n@Injectable()\nexport class OAuth2ErrorService {\n  private readonly logger = new Logger(\"OAuth2ErrorService\");\n\n  constructor(private readonly oAuthService: OAuthService) {}\n\n  handleAuthorizeError(err: unknown, redirectUri: string, state?: string): never {\n    if (err instanceof ErrorWithCode) {\n      const reason = err.data?.[\"reason\"] as string | undefined;\n\n      if (reason && NON_REDIRECTABLE_REASONS.has(reason)) {\n        const statusCode = getHttpStatusCode(err);\n        throw new OAuth2HttpException(\n          {\n            error: err.message,\n            error_description: reason,\n          },\n          statusCode\n        );\n      }\n    }\n\n    const errorRedirectUrl = this.oAuthService.buildErrorRedirectUrl(redirectUri, err, state);\n    throw new OAuth2RedirectException(errorRedirectUrl);\n  }\n\n  handleTokenError(err: unknown): never {\n    if (err instanceof ErrorWithCode) {\n      const statusCode = getHttpStatusCode(err);\n      const reason = err.data?.[\"reason\"] as string | undefined;\n      throw new OAuth2HttpException(","sourceCodeStart":8,"sourceCodeEnd":44,"githubUrl":"https://github.com/calcom/cal.diy/blob/176037d0afbe572f870a3c702985e7cd83fe6c0c/apps/api/v2/src/modules/auth/oauth2/services/oauth2-error.service.ts#L8-L44","documentation":"Thrown by OAuth2ErrorService.handleAuthorizeError when the underlying error is an ErrorWithCode whose data.reason is one of the NON_REDIRECTABLE_REASONS (client_not_found, client_not_approved, client_rejected, redirect_uri_mismatch). Instead of redirecting the user back to the redirect_uri, the server responds directly with an OAuth2HttpException carrying error=err.message and error_description=reason. This is the OAuth2 /authorize endpoint's 'fatal client misconfiguration' path where redirecting would be unsafe or impossible.","triggerScenarios":"A GET to the /v2/oauth/{clientId}/authorize endpoint where: (a) clientId does not match any OAuth client row (client_not_found); (b) the client exists but its approval state is not approved (client_not_approved / client_rejected); (c) the redirect_uri query param does not match any registered redirect URI for the client (redirect_uri_mismatch). The error surfaces as a JSON HTTP error response rather than a 302 redirect.","commonSituations":"Developer copy-pastes the wrong client id from settings; client is still in PENDING approval after creation; redirect_uri in the request uses http://localhost:3000 while the registered URI is http://localhost:3000/callback (trailing path or scheme mismatch); staging client id used against production, or vice versa.","solutions":["Verify the clientId in the authorize URL matches the value shown at https://app.cal.com/settings/platform for the target environment.","Confirm the client is in APPROVED state in the platform OAuth settings; re-request approval if it is PENDING or REJECTED.","Make the redirect_uri query parameter exactly match one of the URIs registered under the client's 'Redirect uris' list (scheme, host, port, and path must all match).","Inspect the error_description field in the response; it will be the literal reason (client_not_found / client_not_approved / client_rejected / redirect_uri_mismatch) telling you which condition failed."],"exampleFix":"// before\nconst url = `https://api.cal.com/v2/oauth/${clientId}/authorize?redirect_uri=http://localhost:3000&state=xyz`;\n\n// after — redirect_uri must match a registered URI exactly\nconst url = `https://api.cal.com/v2/oauth/${clientId}/authorize?redirect_uri=http://localhost:3000/auth/callback&state=xyz`;","handlingStrategy":"validation","validationCode":"// Before redirecting to /authorize, validate the client config you control\nconst CLIENT_ID = process.env.CAL_OAUTH_CLIENT_ID!;\nconst REDIRECT_URI = process.env.CAL_REDIRECT_URI!; // must be registered exactly\nconst APPROVED_STATES = new Set(['APPROVED']);\n\nasync function preflightAuthorize() {\n  const client = await fetch(`/v2/oauth-clients/${CLIENT_ID}`, {\n    headers: { Authorization: `Bearer ${process.env.CAL_ADMIN_API_KEY}` }\n  }).then(r => r.ok ? r.json() : null);\n  if (!client) throw new Error('client_not_found: check CAL_OAUTH_CLIENT_ID');\n  if (!APPROVED_STATES.has(client.approvalStatus)) throw new Error(`client_not_approved: status=${client.approvalStatus}`);\n  if (!client.redirectUris.includes(REDIRECT_URI)) throw new Error(`redirect_uri_mismatch: register ${REDIRECT_URI}`);\n}","typeGuard":"import { ErrorWithCode } from '@calcom/platform-libraries/errors';\n\nconst NON_REDIRECTABLE_REASONS = new Set(['client_not_found','client_not_approved','client_rejected','redirect_uri_mismatch']);\n\nfunction isNonRedirectableAuthorizeError(err: unknown): err is ErrorWithCode {\n  return err instanceof ErrorWithCode\n    && NON_REDIRECTABLE_REASONS.has((err as any).data?.['reason']);\n}","tryCatchPattern":"try {\n  await driveAuthorizeFlow();\n} catch (err) {\n  if (isNonRedirectableAuthorizeError(err)) {\n    // surfaced as HTTP error, not redirect — show config guidance to the integrator\n    renderClientConfigError((err as any).data.reason);\n  } else {\n    // redirect-based error — handle in the redirect_uri callback\n  }\n}","preventionTips":["Register every redirect_uri variant (http/https, trailing slash) you will use before going live.","Keep client id/secret in environment variables keyed per environment to avoid staging/production mix-ups.","Add a preflight check that the client is APPROVED before directing users to /authorize."],"tags":["oauth2","authentication","authorize","client-config","redirect-uri"],"backgroundTag":null,"analyzedSha":"176037d0afbe572f870a3c702985e7cd83fe6c0c","analyzedAt":"2026-08-12T19:12:41.464Z","schemaVersion":2},"datasetVersion":"2026-08-12T23:17:12.415Z"}