calcom/cal.diy · error · UnauthorizedException

ApiKeysService - No API key provided

Error message

ApiKeysService - No API key provided

What it means

Thrown by ApiKeysService.getRequestApiKey when request.authMethod IS API_KEY but the Authorization header is missing or empty after stripping the 'Bearer ' prefix. The auth guard accepted the request as API-key-authenticated, but when the service extracts the actual key value from request.get('Authorization'), the result is null, undefined, or an empty string. This indicates a header parsing issue rather than a missing key.

Source

Thrown at apps/api/v2/src/modules/api-keys/services/api-keys.service.ts:28

import { createApiKeyHandler } from "@calcom/platform-libraries";

@Injectable()
export class ApiKeysService {
  constructor(
    private readonly apiKeysRepository: ApiKeysRepository,
    private readonly config: ConfigService
  ) {}

  async getRequestApiKey(request: ApiAuthGuardRequest) {
    if (request.authMethod !== AuthMethods.API_KEY) {
      throw new UnauthorizedException(
        "ApiKeysService - This endpoint can only be accessed using an API key by providing 'Authorization: Bearer <apiKey>' header"
      );
    }
    const apiKey = request.get("Authorization")?.replace("Bearer ", "");
    if (!apiKey) {
      throw new UnauthorizedException("ApiKeysService - No API key provided");
    }
    return apiKey;
  }

  async createApiKey(authUserId: number, createApiKeyInput: CreateApiKeyInput) {
    if (createApiKeyInput.apiKeyDaysValid && createApiKeyInput.apiKeyNeverExpires) {
      throw new BadRequestException(
        "ApiKeysService -Cannot set both apiKeyDaysValid and apiKeyNeverExpires. It has to be either or none of them."
      );
    }

    const defaultApiKeyDaysValid = 30;
    const apiKeyExpiresAfterDays = createApiKeyInput.apiKeyDaysValid
      ? createApiKeyInput.apiKeyDaysValid
      : defaultApiKeyDaysValid;
    const apiKeyExpiresAt = DateTime.utc().plus({ days: apiKeyExpiresAfterDays }).toJSDate();
    const apiKey = await createApiKeyHandler({
      ctx: {

View on GitHub (pinned to 176037d0af)

Solutions

  1. Verify the raw Authorization header is present in the incoming request using browser dev tools or a network proxy (mitmproxy, Charles).
  2. Check reverse proxy and load balancer configurations to ensure the Authorization header is forwarded unmodified.
  3. Ensure the client sends the full header: 'Authorization: Bearer cal_<actual_key>' with no trailing whitespace after 'Bearer '.
  4. Inspect the ApiAuthGuard/ApiAuthStrategy to confirm it reads from the same header field that getRequestApiKey expects.

Example fix

// before: header value incomplete
headers: { Authorization: 'Bearer ' }

// after: include the full API key
headers: { Authorization: `Bearer cal_${apiKey}` }
Defensive patterns

Strategy: validation

Validate before calling

// Validate the Authorization header is complete before sending
const validateAuthHeader = (header: string | undefined): void => {
  if (!header) throw new Error('Missing Authorization header');
  const parts = header.split(' ');
  if (parts[0] !== 'Bearer') throw new Error('Expected Bearer scheme');
  if (!parts[1] || parts[1].length === 0) throw new Error('Authorization header has no token value');
};

Type guard

const hasValidBearerToken = (h: string | undefined): h is `Bearer ${string}` =>
  typeof h === 'string' && h.startsWith('Bearer ') && h.slice(7).length > 0;

Prevention

When it happens

Trigger: The Authorization header was stripped by a proxy, load balancer, or middleware before reaching the application. The header value is literally 'Bearer ' (with trailing space but no key). A case-sensitivity mismatch in the header name. The request was routed through a path that doesn't forward Authorization headers.

Common situations: A reverse proxy (nginx, Cloudflare) configured to strip or rename the Authorization header. A NestJS middleware or interceptor that consumes and removes the header. The client sending 'Authorization: Bearer' without the actual token value. ApiAuthGuard authenticating via a different mechanism (like a cookie or query param) while the authMethod is set to API_KEY by default or misconfiguration.

Related errors


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