{"record":{"id":"bfa2e5d898b3a3ac","repo":"calcom/cal.diy","slug":"missing-bearer-authorization-header","errorCode":null,"errorMessage":"Missing 'Bearer' Authorization header.","messagePattern":"Missing 'Bearer' Authorization header\\.","errorType":"exception","errorClass":"BadRequestException","httpStatus":400,"severity":"error","filePath":"apps/api/v2/src/modules/oauth-clients/controllers/oauth-flow/oauth-flow.controller.ts","lineNumber":93,"sourceCode":"      );\n    }\n\n    const { id } = await this.tokensRepository.createAuthorizationToken(clientId, userId);\n\n    return res.redirect(`${body.redirectUri}?code=${id}`);\n  }\n\n  @Post(\"/exchange\")\n  @HttpCode(HttpStatus.OK)\n  @DocsExcludeEndpoint()\n  async exchange(\n    @Headers(\"Authorization\") authorization: string,\n    @Param(\"clientId\") clientId: string,\n    @Body() body: ExchangeAuthorizationCodeInput\n  ): Promise<KeysResponseDto> {\n    const authorizeEndpointCode = authorization.replace(\"Bearer \", \"\").trim();\n    if (!authorizeEndpointCode) {\n      throw new BadRequestException(\"Missing 'Bearer' Authorization header.\");\n    }\n\n    const tokens = await this.oAuthFlowService.exchangeAuthorizationToken(\n      authorizeEndpointCode,\n      clientId,\n      body.clientSecret\n    );\n\n    return {\n      status: SUCCESS_STATUS,\n      data: tokens,\n    };\n  }\n\n  @Post(\"/refresh\")\n  @HttpCode(HttpStatus.OK)\n  @UseGuards(ApiAuthGuard)\n  @DocsTags(\"Deprecated: Platform / Managed Users\")","sourceCodeStart":75,"sourceCodeEnd":111,"githubUrl":"https://github.com/calcom/cal.diy/blob/176037d0afbe572f870a3c702985e7cd83fe6c0c/apps/api/v2/src/modules/oauth-clients/controllers/oauth-flow/oauth-flow.controller.ts#L75-L111","documentation":"Thrown by POST /exchange when the Authorization header is absent or yields an empty string after .replace('Bearer ', '').trim(). The endpoint expects the one-time authorization code to be delivered as a Bearer token in the Authorization header (not in the body). Missing/malformed header → BadRequestException (HTTP 400).","triggerScenarios":"Calling POST /exchange without setting the Authorization header at all; sending 'Bearer' with no trailing token; sending 'Bearer ' (trailing space only); sending the code in the request body instead of the header; sending a header with a different scheme like 'Basic'.","commonSituations":"Client library that puts credentials in the body by default; a header-stripping proxy or CORS preflight that drops Authorization; a typo in the header name; sending the raw code without the 'Bearer ' prefix.","solutions":["Set the header exactly: Authorization: Bearer <authorizationCode> where authorizationCode is the code returned from /authorize.","Verify the code is non-empty before constructing the header.","Ensure no proxy/gateway strips the Authorization header.","Use the same code value from the redirect ?code= param, not the client secret."],"exampleFix":"// before\nawait fetch(`/v2/oauth-clients/${clientId}/exchange`, { method: 'POST', body: JSON.stringify({ clientSecret }) });\n\n// after\nawait fetch(`/v2/oauth-clients/${clientId}/exchange`, {\n  method: 'POST',\n  headers: { Authorization: `Bearer ${code}`, 'Content-Type': 'application/json' },\n  body: JSON.stringify({ clientSecret }),\n});","handlingStrategy":"validation","validationCode":"// Build and validate the Bearer header before sending\nfunction bearerHeader(code: unknown) {\n  if (typeof code !== 'string' || code.trim() === '') {\n    throw new Error('authorization code is required');\n  }\n  return { Authorization: `Bearer ${code}` };\n}\nawait fetch(`/v2/oauth-clients/${clientId}/exchange`, {\n  method: 'POST',\n  headers: { ...bearerHeader(code), 'Content-Type': 'application/json' },\n  body: JSON.stringify({ clientSecret }),\n});","typeGuard":"function isNonEmptyBearerCode(value: unknown): value is string {\n  return typeof value === 'string' && value.trim().length > 0;\n}","tryCatchPattern":"if (!code) throw new Error('Missing authorization code for Bearer header');\n// (No try/catch needed if validated up front; the server error is purely a client omission.)","preventionTips":["Always set Authorization: Bearer <code> on /exchange.","Take the code verbatim from the redirect ?code= param.","Ensure proxies do not strip the Authorization header."],"tags":["oauth","auth-header","bearer","exchange","http"],"backgroundTag":null,"analyzedSha":"176037d0afbe572f870a3c702985e7cd83fe6c0c","analyzedAt":"2026-08-12T19:12:41.464Z","schemaVersion":2},"datasetVersion":"2026-08-12T23:17:12.415Z"}