Back to Blog
Security · 14 min read

Security, GDPR & Compliance: How We Protect Every Byte

Turnstile, Content Security Policy, OAuth PKCE, per-tenant isolation, cookie consent, right to erasure and premium feature guards — Cadences' multi-layer security explained piece by piece.

Gonzalo Monzón

Gonzalo Monzón

· Founder & CTO

Digital security and data protection
All security layers active

Security isn't a feature you add later. In Cadences, it's an architectural decision that affects every layer of the stack: from how each organization's data is isolated to how a click on a registration button is validated. This article explains the complete security model.

🛡️ Defense in Depth Model

Cadences implements 7 independent security layers. If one fails, the rest keep protecting. There's no single point of failure in the security chain.

Overview

Multi-Layer Security Map

Every request reaching Cadences passes through multiple verification layers before touching a single piece of data:

Layer Mechanism Protection
1. EdgeCloudflare WAF + DDoSVolumetric attacks, HTTP-level SQL injection
2. Bot ProtectionTurnstile (invisible)Bots, scraping, fake registrations
3. AuthenticationOAuth 2.0 + PKCE + JWTUnauthorized access, session hijacking
4. AuthorizationRBAC + Feature GuardsPrivilege escalation, premium feature access
5. IsolationD1 per tenant + V8 isolatesCross-tenant data leak
6. TransportTLS 1.3 + HSTS + CSPMITM, XSS, clickjacking
7. SecretsCloudflare Secrets + env varsAPI key exposure, token leaks
Layer 2

Turnstile: Invisible Anti-Bot Protection

Cadences uses Cloudflare Turnstile instead of traditional CAPTCHAs. The difference is critical: Turnstile verifies the user is human without interrupting the experience. No puzzles, no "select all traffic lights".

🤖

Traditional CAPTCHA

  • ❌ Interrupts user flow
  • ❌ Poor accessibility
  • ❌ Google tracks the user
  • ❌ 8-15% abandonment rate
🛡️

Cloudflare Turnstile

  • ✅ Invisible — zero friction
  • ✅ Accessible by default
  • ✅ No third-party tracking
  • ✅ ~0% abandonment rate
Worker: Turnstile Verification
async function verifyTurnstile(token: string, ip: string) {
  const response = await fetch(
    'https://challenges.cloudflare.com/turnstile/v0/siteverify',
    {
      method: 'POST',
      headers: { 'Content-Type': 'application/json' },
      body: JSON.stringify({
        secret: env.TURNSTILE_SECRET_KEY,
        response: token,
        remoteip: ip,
      }),
    }
  );

  const result = await response.json();

  if (!result.success) {
    throw new Error('Bot detected — request rejected');
  }

  return result;
}

Turnstile is applied on all critical forms: registration, login, contact and payments. The token is verified server-side in the Worker, never on the client.

Layer 3

Authentication: OAuth 2.0 + PKCE + JWT

Cadences supports two distinct authentication flows depending on context:

🌐 Web App (GIS Flow)

  1. 1. Redirect to Google OAuth
  2. 2. Google returns auth code
  3. 3. Worker validates code + client_secret
  4. 4. JWT signed with HMAC-SHA256 is generated
  5. 5. JWT includes orgId + userId + role + exp

🖥️ Desktop (PKCE Flow)

  1. 1. Generate code_verifier + code_challenge
  2. 2. Open browser with challenge
  3. 3. Localhost callback receives code
  4. 4. Exchange code + verifier for tokens
  5. 5. No client_secret on the device

⚠️ Why PKCE for Desktop?

Desktop apps cannot securely store a client_secret — any user can decompile the binary. PKCE (Proof Key for Code Exchange) eliminates that need: the cryptographic challenge replaces the secret, and only the process that started the flow can complete it.

Layer 4

Premium Feature Guards

Not all users have access to the same features. Cadences implements a feature guard system that protects costly APIs and premium functionality:

Worker: Premium Feature Guard
class PremiumAPIAccessError extends Error {
  constructor(feature: string) {
    super(`Premium feature "${feature}" not available`);
    this.name = 'PremiumAPIAccessError';
  }
}

function requirePremiumFeature(org: Org, feature: string) {
  const allowed = org.plan?.features || [];

  if (!allowed.includes(feature)) {
    throw new PremiumAPIAccessError(feature);
  }
}

// Usage example in Voice AI endpoint
requirePremiumFeature(org, 'voice_calls');
requirePremiumFeature(org, 'elevenlabs_tts');

This is especially important for pay-per-use APIs (ElevenLabs, Twilio, OpenAI). A free plan user cannot generate voice calls no matter how well they know the endpoint URL.

🆓

Free Plan

Basic CRM, 1 storefront, limited AI agents, no voice, no TTS

Pro Plan

Voice calls, TTS, unlimited agents, multiple storefronts, webhooks

🏢

Enterprise Plan

SSO, API access, custom agents, dedicated support, 99.9% SLA

Layer 5

Total Data Isolation

Data isolation in Cadences isn't a software filter — it's an architectural guarantee. Each organization has its own D1 database (SQLite at the edge). There's no WHERE org_id = ? — the entire database belongs to a single tenant.

🔒

Data Isolation

Physical impossibility of accessing another tenant's data. No cross-tenant queries because there are no shared tables.

Compute Isolation

Each request executes in an independent V8 isolate with its own CPU and memory limits.

📁

Storage Isolation

Files in R2 under per-organization prefix. KV namespaces with org-scoped keys. No collision possible.

🔑

Auth Isolation

JWTs signed per-org with HMAC-SHA256. A token from org A never works against org B.

Layer 6

Content Security Policy & Headers

Every HTTP response from Cadences includes security headers that block attacks before the browser executes malicious code:

Security Headers
// Content Security Policy — controls what the browser can load
Content-Security-Policy:
  default-src 'self';
  script-src 'self' 'unsafe-inline' challenges.cloudflare.com;
  style-src 'self' 'unsafe-inline' fonts.googleapis.com;
  img-src 'self' data: images.unsplash.com *.googleusercontent.com;
  connect-src 'self' *.cadences.app api.elevenlabs.io;
  frame-src challenges.cloudflare.com;

// Other security headers
Strict-Transport-Security: max-age=31536000; includeSubDomains
X-Content-Type-Options: nosniff
X-Frame-Options: DENY
Referrer-Policy: strict-origin-when-cross-origin
Permissions-Policy: camera=(), microphone=(self), geolocation=()
Header What It Prevents
Content-Security-PolicyXSS, script injection, data exfiltration
Strict-Transport-SecurityDowngrade attacks, HTTP MITM
X-Frame-Options: DENYClickjacking via iframes
X-Content-Type-OptionsMIME sniffing attacks
Permissions-PolicyUnauthorized camera, mic, GPS access

In Electron apps (CadencesLab, Audio Hub), context isolation is also applied: the app code has no direct access to Node.js APIs. All communication goes through a preload bridge with typed IPC.

Compliance

GDPR: Real Compliance, Not Just a Banner

GDPR compliance isn't achieved with a cookie banner. It's achieved with architectural decisions that enable exercising every right the regulation establishes:

📋 Right of Access (Art. 15)

Complete user data export in JSON/CSV format. A single button in Synapse Studio generates the full package: contacts, deals, activities, files.

✏️ Right to Rectification (Art. 16)

All data is editable by the owning user. No locked fields, no opaque processes. Edit, save, done.

🗑️ Right to Erasure (Art. 17)

This is where the database-per-tenant architecture shines. Want to delete all data for an organization?

// GDPR Article 17: Right to erasure
await env.CF_API.deleteD1Database(org.dbId);
await env.R2.deletePrefix(`org/${orgId}/`);
await env.KV.deletePrefix(`org:${orgId}:`);
// The entire organization vanishes. No remnants.

No soft-delete. No flags. DROP DATABASE. Total isolation means total deletion.

📦 Right to Data Portability (Art. 20)

Export in standard formats (JSON, CSV) of all user data. Compatible with import into other CRMs.

🍪 Cookie Consent (Art. 7)

Consent banner on every Storefront. No tracking until the user explicitly accepts. Google Analytics and third-party scripts blocked by default.

Layer 7

Secrets Management

Cadences manages dozens of API keys and secrets from external services: Google OAuth, Twilio, ElevenLabs, Stripe, DeepSeek, OpenAI, Anthropic. None of these secrets appear in the source code:

How They're Stored

  • • Cloudflare Secrets (encrypted at rest)
  • • Environment variables in wrangler.toml (dev)
  • • Per-environment secrets (staging/production)
  • • Periodic OAuth token rotation

Never Done

  • • Hardcoded secrets in source code
  • • Secrets in localStorage or cookies
  • • API keys in URLs or query params
  • • Logs with sensitive data
Protection

Rate Limiting with Durable Objects

Each organization has its own rate limiting Durable Object. We don't share counters across tenants. This means:

Endpoint Limit Window
General API1,000 reqper minute / org
Auth (login/register)10 reqper minute / IP
ElevenLabs TTS50 reqper hour / org (Pro plan)
Voice Calls (Twilio)20 callsper hour / org
AI Agents100 execper hour / org
Incoming Webhooks500 reqper hour / org

The rate limiter uses a sliding window implemented with Durable Objects. Each org has its own DO, meaning abuse from org A doesn't affect org B (no noisy neighbor problem).

Checklist

Complete Security Checklist

🔐 Authentication

  • ✅ OAuth 2.0 with Google
  • ✅ PKCE for desktop apps
  • ✅ JWT with configurable expiration
  • ✅ Encrypted refresh tokens
  • ✅ Server-side session invalidation

🛡️ Infrastructure

  • ✅ Cloudflare WAF + DDoS protection
  • ✅ TLS 1.3 everywhere
  • ✅ HSTS with preload
  • ✅ Zero trust networking
  • ✅ Edge-native (no own servers)

📊 Data

  • ✅ Database per tenant
  • ✅ Encryption at rest (D1)
  • ✅ Automatic daily backups
  • ✅ GDPR data export
  • ✅ Right to erasure (DROP DB)

🖥️ Desktop Apps

  • ✅ Context isolation (Electron)
  • ✅ Typed IPC bridge
  • ✅ No nodeIntegration
  • ✅ CSP in renderer
  • ✅ Signed auto-update

Is Your Platform GDPR Compliant?

If you're building a SaaS and need to comply with privacy regulations, Cadences already does it for you. Every organization operating on Cadences automatically inherits the complete security model.

Start with Cadences
Summary

Conclusion

Security in Cadences isn't a checkbox — it's an emergent property of the architecture. Per-tenant isolation isn't a SQL filter, it's a separate database. Anti-bot protection isn't an annoying CAPTCHA, it's invisible Turnstile. GDPR compliance isn't a cookie banner, it's the ability to DROP DATABASE and have everything disappear.

Each layer works independently. If a vulnerability is discovered in Turnstile tomorrow, the other 6 layers keep protecting. If a JWT is compromised, the rate limiter and feature guards still block unauthorized access. Defense in depth isn't a buzzword — it's the only serious way to build software in 2026.

The best security is the kind users don't notice but attackers can't overcome.