Skip to content

Cloudflare Adapter ​

The Cloudflare adapter provides Cloudflare-specific integrations for AuthHero, including custom domain management, caching, and optional logging solutions.

Features ​

  • Custom Domains: Manage custom domains via Cloudflare API with automatic SSL certificates
  • Cache: Cloudflare Cache API integration for high-performance caching
  • Rate Limit (optional): Workers Rate Limiter bindings wired into AuthHero's pre-login, brute-force, and pre-user-registration scopes
  • Logs (optional): Two options for authentication logs:
    • Analytics Engine: Low-latency writes with SQL querying (90-day retention). Also returns the log-derived analytics and stats adapters.
    • R2 SQL: Long-term storage with unlimited retention
  • Edge Compatible: Works in Cloudflare Workers and standard Node.js environments
  • Global Distribution: Leverage Cloudflare's global network

Installation ​

bash
npm install @authhero/cloudflare-adapter

Quick Start ​

Basic Setup ​

typescript
import createAdapters from "@authhero/cloudflare-adapter";

const adapters = createAdapters({
  // Custom domains configuration (required)
  zoneId: "your-cloudflare-zone-id",
  authKey: "your-cloudflare-api-key",
  authEmail: "your-cloudflare-email",
  customDomainAdapter: yourDatabaseCustomDomainsAdapter,

  // Cache configuration (optional)
  cacheName: "default",
  defaultTtlSeconds: 3600,
  keyPrefix: "authhero:",

  // Rate limit bindings (optional — see Rate Limit Adapter docs)
  // Bindings are declared in wrangler.toml under [[unsafe.bindings]] with
  // type = "ratelimit". Any scope you omit fails open.
  rateLimitBindings: {
    "pre-login": env.RATE_LIMIT_PRE_LOGIN,
    "brute-force": env.RATE_LIMIT_BRUTE_FORCE,
    "pre-user-registration": env.RATE_LIMIT_PRE_REGISTRATION,
  },

  // Analytics Engine logs configuration (optional, recommended for Workers)
  analyticsEngineLogs: {
    analyticsEngineBinding: env.AUTH_LOGS,
    accountId: env.CLOUDFLARE_ACCOUNT_ID,
    apiToken: env.ANALYTICS_ENGINE_API_TOKEN,
  },

  // OR R2 SQL logs configuration (optional, for long-term storage)
  r2SqlLogs: {
    authToken: process.env.R2_SQL_AUTH_TOKEN,
    warehouseName: process.env.R2_WAREHOUSE_NAME,
    namespace: "default",
    tableName: "logs",
  },
});

// Use the adapters. `analytics` and `stats` are only present when
// `analyticsEngineLogs` is configured — they are derived from the same events.
const { customDomains, cache, logs, analytics, stats } = adapters;

Adapters ​

Custom Domains ​

Manage custom domains through the Cloudflare API with automatic SSL certificate provisioning and DNS configuration.

Key Features:

  • Automatic SSL certificate management
  • DNS configuration through Cloudflare API
  • Enterprise and non-enterprise mode support
  • Full CRUD operations for domains

Learn more about Custom Domains →

Cache ​

High-performance caching using Cloudflare's Cache API for fast data retrieval at the edge.

Key Features:

  • Edge-based caching for minimal latency
  • Configurable TTL per cache entry
  • Key prefix support for namespacing
  • Simple get/set/delete operations

Learn more about Cache →

Rate Limit (Optional) ​

Wire AuthHero's pre-login, brute-force, and pre-user-registration scopes to Cloudflare Workers Rate Limiter bindings. Pass rateLimitBindings to createAdapters and the returned object will include a rateLimit field that you merge into your data adapter. The pre-login scope is additionally gated by the tenant's attack_protection.suspicious_ip_throttling.enabled flag.

Key Features:

  • Short-window abuse protection at the edge (10s or 60s windows)
  • Per-scope binding so limits differ by abuse vector
  • Fails open if a binding is misconfigured or absent

Learn more about the Rate Limit adapter →

Logs (Optional) ​

Choose between two logging solutions based on your needs:

Analytics Engine ​

Best for real-time analytics and recent logs with near-zero write latency.

Key Features:

  • Fire-and-forget writes (~0ms latency)
  • SQL-based querying
  • 90-day retention (configurable)
  • Free tier available
  • Ideal for Workers

Learn more about Analytics Engine →

R2 SQL ​

Best for long-term storage and compliance requirements with unlimited retention.

Key Features:

  • Unlimited retention period
  • Apache Iceberg format
  • Pipeline-based ingestion
  • SQL querying via R2 SQL
  • Pay-as-you-go pricing

Learn more about R2 SQL →

Complete Integration Example ​

Here's a complete example integrating all adapters:

typescript
import createAdapters from "@authhero/cloudflare-adapter";
import { createKyselyAdapter } from "@authhero/kysely-adapter";

// Create database adapter for custom domains
const database = createKyselyAdapter(db);

// Create Cloudflare adapters
const cloudflareAdapters = createAdapters({
  // Custom domains
  zoneId: process.env.CLOUDFLARE_ZONE_ID!,
  authKey: process.env.CLOUDFLARE_AUTH_KEY!,
  authEmail: process.env.CLOUDFLARE_AUTH_EMAIL!,
  customDomainAdapter: database.customDomains,

  // Cache
  cacheName: "authhero-cache",
  defaultTtlSeconds: 3600,
  keyPrefix: "authhero:",

  // Logs (choose one: Analytics Engine or R2 SQL)
  analyticsEngineLogs: {
    analyticsEngineBinding: env.AUTH_LOGS,
    accountId: process.env.CLOUDFLARE_ACCOUNT_ID!,
    apiToken: process.env.ANALYTICS_ENGINE_API_TOKEN!,
  },
});

// Use in your application
export const dataAdapters = {
  ...database,
  cache: cloudflareAdapters.cache,
  customDomains: cloudflareAdapters.customDomains,
  // The three log-derived adapters must move together — see the note below
  logs: cloudflareAdapters.logs,
  analytics: cloudflareAdapters.analytics,
  stats: cloudflareAdapters.stats,
  rateLimit: cloudflareAdapters.rateLimit, // optional — undefined if no bindings configured
};

Move logs, analytics and stats together

Configuring analyticsEngineLogs makes createAdapters return all three of logs, analytics and stats, because all three are derived from the same log events. If you forward only logs and leave analytics/stats on the SQL database adapter, /api/v2/stats/daily, /api/v2/stats/active-users and the analytics endpoints keep reading the SQL logs table — which no longer receives writes once logs go to Analytics Engine — and report zeros.

Environment Variables ​

env
# Custom Domains (required)
CLOUDFLARE_ZONE_ID=your_zone_id
CLOUDFLARE_AUTH_KEY=your_api_key
CLOUDFLARE_AUTH_EMAIL=your_email
CLOUDFLARE_ENTERPRISE=false

# Cache (optional)
CACHE_NAME=default
CACHE_DEFAULT_TTL=3600
CACHE_KEY_PREFIX=authhero:

# Analytics Engine Logs (optional)
CLOUDFLARE_ACCOUNT_ID=your_account_id
ANALYTICS_ENGINE_API_TOKEN=your_analytics_token
ANALYTICS_ENGINE_DATASET=authhero_logs

# R2 SQL Logs (optional, alternative to Analytics Engine)
PIPELINE_ENDPOINT=https://your-stream-id.ingest.cloudflare.com
R2_SQL_AUTH_TOKEN=your_r2_sql_token
R2_WAREHOUSE_NAME=your_warehouse_name
R2_SQL_NAMESPACE=default
R2_SQL_TABLE=logs

TypeScript Support ​

The package includes full TypeScript definitions:

typescript
import type {
  CloudflareConfig,
  CloudflareAdapters,
  R2SQLLogsAdapterConfig,
  AnalyticsEngineLogsAdapterConfig,
  AnalyticsEngineDataset,
} from "@authhero/cloudflare-adapter";

Best Practices ​

1. Error Handling ​

Always implement proper error handling:

typescript
try {
  await customDomains.create(tenantId, domainData);
} catch (error) {
  // Log error for debugging
  console.error("Failed to create domain:", error);

  // Optionally log to your logs adapter
  if (logs) {
    await logs.create(tenantId, {
      type: "api_error",
      date: new Date().toISOString(),
      ip: request.ip,
      user_agent: request.headers["user-agent"],
      isMobile: false,
      description: `Failed to create domain: ${error.message}`,
    });
  }

  throw error;
}

2. Cache Strategy ​

Implement cache-aside pattern for optimal performance:

typescript
async function getDataWithCache<T>(
  key: string,
  fetcher: () => Promise<T>,
  ttl: number = 300,
): Promise<T> {
  // Try cache first
  const cached = await cache.get<T>(key);
  if (cached) return cached;

  // Fetch from source
  const data = await fetcher();

  // Cache for next time
  await cache.set(key, data, ttl);

  return data;
}

3. Logging Strategy ​

Choose the right logging solution for your use case:

  • Analytics Engine: Real-time dashboards, recent activity monitoring
  • R2 SQL: Compliance, audit trails, long-term analytics
  • Both: Use passthrough adapter to write to both simultaneously

Next Steps ​

Dual-licensed: AGPL-3.0-only or commercial license.