calcom/cal.diy · error · BadRequestException

Missing 'Bearer' Authorization header.

Error message

Missing 'Bearer' Authorization header.

What it means

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).

Source

Thrown at apps/api/v2/src/modules/oauth-clients/controllers/oauth-flow/oauth-flow.controller.ts:93

      );
    }

    const { id } = await this.tokensRepository.createAuthorizationToken(clientId, userId);

    return res.redirect(`${body.redirectUri}?code=${id}`);
  }

  @Post("/exchange")
  @HttpCode(HttpStatus.OK)
  @DocsExcludeEndpoint()
  async exchange(
    @Headers("Authorization") authorization: string,
    @Param("clientId") clientId: string,
    @Body() body: ExchangeAuthorizationCodeInput
  ): Promise<KeysResponseDto> {
    const authorizeEndpointCode = authorization.replace("Bearer ", "").trim();
    if (!authorizeEndpointCode) {
      throw new BadRequestException("Missing 'Bearer' Authorization header.");
    }

    const tokens = await this.oAuthFlowService.exchangeAuthorizationToken(
      authorizeEndpointCode,
      clientId,
      body.clientSecret
    );

    return {
      status: SUCCESS_STATUS,
      data: tokens,
    };
  }

  @Post("/refresh")
  @HttpCode(HttpStatus.OK)
  @UseGuards(ApiAuthGuard)
  @DocsTags("Deprecated: Platform / Managed Users")

View on GitHub (pinned to 176037d0af)

Solutions

  1. Set the header exactly: Authorization: Bearer <authorizationCode> where authorizationCode is the code returned from /authorize.
  2. Verify the code is non-empty before constructing the header.
  3. Ensure no proxy/gateway strips the Authorization header.
  4. Use the same code value from the redirect ?code= param, not the client secret.

Example fix

// before
await fetch(`/v2/oauth-clients/${clientId}/exchange`, { method: 'POST', body: JSON.stringify({ clientSecret }) });

// after
await fetch(`/v2/oauth-clients/${clientId}/exchange`, {
  method: 'POST',
  headers: { Authorization: `Bearer ${code}`, 'Content-Type': 'application/json' },
  body: JSON.stringify({ clientSecret }),
});
Defensive patterns

Strategy: validation

Validate before calling

// Build and validate the Bearer header before sending
function bearerHeader(code: unknown) {
  if (typeof code !== 'string' || code.trim() === '') {
    throw new Error('authorization code is required');
  }
  return { Authorization: `Bearer ${code}` };
}
await fetch(`/v2/oauth-clients/${clientId}/exchange`, {
  method: 'POST',
  headers: { ...bearerHeader(code), 'Content-Type': 'application/json' },
  body: JSON.stringify({ clientSecret }),
});

Type guard

function isNonEmptyBearerCode(value: unknown): value is string {
  return typeof value === 'string' && value.trim().length > 0;
}

Try / catch

if (!code) throw new Error('Missing authorization code for Bearer header');
// (No try/catch needed if validated up front; the server error is purely a client omission.)

Prevention

When it happens

Trigger: 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'.

Common situations: 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.

Related errors


AI-assisted analysis of calcom/cal.diy@176037d0af (2026-08-12). Data as JSON: /api/errors/bfa2e5d898b3a3ac. Report an issue: GitHub.