Skip to content

[API v2] License validation bug: checkLicense checks data.status but API returns data.valid #26610

@nicfab

Description

@nicfab

Issue Summary

Self-hosted Cal.com instance with API v2

The API v2 license validation in deployments.service.js fails on self-hosted instances because it checks for data.status property, but the Cal.com license API (https://console.cal.com/api/license/{key}) returns data.valid property instead.

This causes all API v2 requests with API key authentication to fail with error "ApiAuthStrategy - api key - Invalid or missing CALCOM_LICENSE_KEY environment variable" even when the Enterprise license key is valid and properly configured.

The bug is in file apps/api/v2/src/modules/deployments/deployments.service.ts at the checkLicense() method.

Steps to Reproduce

  1. Set up self-hosted Cal.com with API v2 container built from source
  2. Configure valid Enterprise license key (CALCOM_LICENSE_KEY=cal_live_xxx)
  3. Configure Redis and all required environment variables for API v2
  4. Start API v2 container (separate from main web app)
  5. Create an API key from the Cal.com UI (Settings > Security)
  6. Make an API request to /api/v2/bookings with the API key:
curl -X GET "https://your-self-hosted-domain.com/api/v2/bookings" \
  -H "Authorization: Bearer cal_your_api_key" \
  -H "Content-Type: application/json" \
  -H "cal-api-version: 2024-08-13"
  1. Request fails with 401 Unauthorized

Actual Results

API returns 401 error:

{
  "status": "error",
  "error": {
    "code": "UnauthorizedException",
    "message": "ApiAuthStrategy - api key - Invalid or missing CALCOM_LICENSE_KEY environment variable"
  }
}

The license API response is cached in Redis as:

{"valid": true}

But the code in deployments.service.ts checks data.status:

return data.status;  // Returns undefined because property is "valid", not "status"

Expected Results

API v2 requests on self-hosted instances should succeed when a valid Enterprise license key is configured. The checkLicense() method should correctly read the valid property from the license API response.

Technical details

  • Deployment type: Self-hosted
  • Cal.com version: Latest (Docker build from source - January 2026)
  • Node.js version: 20
  • Infrastructure: Docker containers (calcom-web on port 3000, calcom-api-v2 on port 5555, PostgreSQL, Redis)
  • License: Valid Enterprise license (cal_live_xxx)
  • OS: Debian 12

Self-hosted setup:

  • Main Cal.com web app: Custom Docker build from apps/web
  • API v2: Separate container built from apps/api/v2/Dockerfile
  • NGINX reverse proxy routing /api/v2 to API v2 container

Relevant code location:

  • apps/api/v2/src/modules/deployments/deployments.service.ts - checkLicense() method
  • apps/api/v2/src/modules/auth/strategies/api-auth/api-auth.strategy.ts - calls deploymentsService.checkLicense()

License API test:

$ curl -s "https://console.cal.com/api/license/cal_live_xxx"
{"valid":true}

Evidence

1. Redis cache showing the response from license API:

$ docker exec calcom-redis redis-cli GET "api-v2-license-key-goblin-url-cal_live_xxx"
{"valid":true}

2. Code in deployments.service.js (compiled):

const data = (await response.json());
// ...
return data.status;  // BUG: should be data.valid

3. Workaround confirms the bug:

Manually setting the cache with {"status":true} instead of {"valid":true} makes the API work on self-hosted instance:

$ docker exec calcom-redis redis-cli SET "api-v2-license-key-goblin-url-cal_live_xxx" '{"status":true}' EX 86400
OK

$ curl -s "https://your-self-hosted-domain.com/api/v2/bookings" -H "Authorization: Bearer cal_xxx" -H "cal-api-version: 2024-08-13"
{"status":"success","data":[...]}  # Works!

Suggested Fix

In apps/api/v2/src/modules/deployments/deployments.service.ts, change:

return data.status;

to:

return data.valid;

Metadata

Metadata

Assignees

No one assigned

    Labels

    🐛 bugSomething isn't working

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions