HelloJohn / docs
Security

CORS Configuration

Configure Cross-Origin Resource Sharing (CORS) for HelloJohn — allowed origins, preflight requests, and common setups.

CORS Configuration

HelloJohn's API enforces CORS to ensure only authorized origins can make cross-origin requests from browsers. This page explains how CORS works in HelloJohn and how to configure it correctly.


How HelloJohn Handles CORS

HelloJohn enforces a whitelist of allowed origins per tenant. Only requests from listed origins receive the Access-Control-Allow-Origin header. Unlisted origins receive a CORS error in the browser.

Your backend-to-HelloJohn requests (server-side) are not subject to CORS — CORS only applies to browser-based requests.


Configuring Allowed Origins

Via Dashboard

Go to Tenant Settings → Security → Allowed Origins and add your application domains.

Via Admin API

curl -X PATCH "https://api.hellojohn.dev/v1/admin/config" \
  -H "Authorization: Bearer sk_live_abc123" \
  -H "X-Tenant-ID: tnt_01HABCDEF654321" \
  -H "Content-Type: application/json" \
  -d '{
    "allowed_origins": [
      "https://app.example.com",
      "https://www.example.com",
      "https://staging.example.com"
    ]
  }'

Rules:

  • Must include the full scheme (https://)
  • No trailing slashes
  • Port must be included if non-standard (e.g., http://localhost:3000)
  • Wildcards (*) are not supported — list each origin explicitly

Local Development

Add http://localhost:3000 (or your dev port) to allowed origins during development:

curl -X PATCH "https://api.hellojohn.dev/v1/admin/config" \
  -H "Authorization: Bearer sk_live_abc123" \
  -H "X-Tenant-ID: tnt_01HABCDEF654321" \
  -H "Content-Type: application/json" \
  -d '{
    "allowed_origins": [
      "https://app.example.com",
      "http://localhost:3000",
      "http://localhost:5173"
    ]
  }'

Remove localhost from production tenant configuration. Keep a separate tenant for local development.


CORS Headers Returned by HelloJohn

For requests from allowed origins:

Access-Control-Allow-Origin: https://app.example.com
Access-Control-Allow-Methods: GET, POST, PUT, PATCH, DELETE, OPTIONS
Access-Control-Allow-Headers: Content-Type, Authorization, X-Tenant-ID
Access-Control-Allow-Credentials: true
Access-Control-Max-Age: 86400

Access-Control-Allow-Credentials: true is required for cookies (refresh tokens). This is why wildcard origins (*) cannot be used — browsers reject credentials with *.


Preflight Requests

Browsers send an OPTIONS preflight request before non-simple requests. HelloJohn handles preflight automatically — no configuration needed on your side.

If you see preflight requests failing, check:

  1. The origin is in your allowed origins list
  2. The X-Tenant-ID header is listed in Access-Control-Allow-Headers (it is by default)
  3. You're using https:// — HTTP origins may be blocked depending on configuration

Backend Proxy Pattern

The most secure pattern routes all HelloJohn calls through your own backend, eliminating browser CORS entirely:

Browser → Your Backend → HelloJohn API
// Your backend (Express)
app.post("/auth/sign-in", async (req, res) => {
  // Proxy to HelloJohn — no CORS issues (server-to-server)
  const hjRes = await fetch("https://api.hellojohn.dev/v1/auth/sign-in", {
    method: "POST",
    headers: {
      "X-Tenant-ID": process.env.HELLOJOHN_TENANT_ID!,
      "Content-Type": "application/json",
    },
    body: JSON.stringify(req.body),
  });

  const data = await hjRes.json();

  // Set refresh token in HttpOnly cookie (browser can't read it)
  res.cookie("hj_refresh_token", data.refresh_token, {
    httpOnly: true,
    secure: true,
    sameSite: "lax",
    path: "/auth/refresh",
  });

  res.json({ access_token: data.access_token });
});

Benefits:

  • No CORS configuration needed on HelloJohn
  • Refresh token never exposed to browser JavaScript
  • Your backend can add extra validation logic

Common CORS Errors

No 'Access-Control-Allow-Origin' header

The origin making the request is not in the allowed origins list.

Fix: Add the origin to your tenant's allowed origins via the dashboard or API.

CORS error on localhost

Your local development origin is not in the list.

Fix: Add http://localhost:{port} to allowed origins.

Credentials flag is set but no 'Access-Control-Allow-Credentials'

This shouldn't happen with HelloJohn (credentials are always allowed for whitelisted origins), but can occur if you're using a self-hosted instance with misconfigured proxy headers.

Fix: Ensure your reverse proxy forwards the Origin header to HelloJohn:

proxy_set_header Origin $http_origin;

Request header not allowed

A custom header in your request is not in the CORS Access-Control-Allow-Headers list.

Fix: If you're adding custom headers to HelloJohn API requests, open a support request to have them added.


Self-Hosted CORS Configuration

For self-hosted HelloJohn, configure allowed origins in environment variables:

HELLOJOHN_ALLOWED_ORIGINS=https://app.example.com,https://www.example.com,http://localhost:3000

Or in your reverse proxy (nginx):

map $http_origin $cors_origin {
  default "";
  "https://app.example.com" $http_origin;
  "https://www.example.com" $http_origin;
  "http://localhost:3000"   $http_origin;
}

server {
  location /v1/ {
    add_header Access-Control-Allow-Origin $cors_origin always;
    add_header Access-Control-Allow-Credentials true always;
    add_header Access-Control-Allow-Methods "GET, POST, PUT, PATCH, DELETE, OPTIONS" always;
    add_header Access-Control-Allow-Headers "Content-Type, Authorization, X-Tenant-ID" always;

    if ($request_method = OPTIONS) {
      add_header Access-Control-Max-Age 86400;
      return 204;
    }

    proxy_pass http://hellojohn:8080;
  }
}

On this page