klaviyo-security-basics

'Apply Klaviyo security best practices for API key management and access

Allowed Tools

ReadWriteEditGrep

Provided by Plugin

klaviyo-pack

Claude Code skill pack for Klaviyo (24 skills)

saas packs v1.7.0
View Plugin

Installation

This skill is included in the klaviyo-pack plugin:

/plugin install klaviyo-pack@claude-code-plugins-plus

Click to copy

Instructions

Klaviyo Security Basics

Overview

Security best practices for Klaviyo: API key types, OAuth scopes, webhook HMAC-SHA256 signature verification, and secret rotation procedures.

Prerequisites

  • Klaviyo account with API key access
  • Understanding of environment variables and secret management
  • Access to Klaviyo dashboard (Settings > API Keys)

Instructions

Step 1: Understand Key Types

Key Type Format Use Case Sensitivity
Private API Key pk_* (40+ chars) Server-side REST API CRITICAL -- never expose client-side
Public API Key 6 alphanumeric chars Client-side Track/Identify only Low -- safe in browser JS

Private keys authenticate via Authorization: Klaviyo-API-Key pk*** header. Public keys pass as companyid query parameter.

Step 2: Store Keys in Environment Variables

Keep every private key and the webhook signing secret out of source: load them

from .env (git-ignored) through a validated config loader that throws on a

missing secret, so misconfiguration fails at boot instead of at first API call.


// src/config/klaviyo.ts -- validated config loader (skeleton)
export const klaviyoConfig = {
  privateKey: requireEnv('KLAVIYO_PRIVATE_KEY'),        // throws if absent
  publicKey: process.env.KLAVIYO_PUBLIC_KEY || '',
  webhookSecret: process.env.KLAVIYO_WEBHOOK_SIGNING_SECRET || '',
};

Full .env template, .gitignore entries, and the requireEnv helper:

implementation.md → Environment Variable Configuration.

Step 3: Scope Keys per Environment (Least Privilege)

Issue a separate key for each environment with only the scopes that environment

needs — read-only in dev and CI, full read/write in staging, the exact production

scope set in prod — so a leaked key has the smallest possible blast radius. Scope

table and per-environment env-var layout:

implementation.md → Least-Privilege API Key Scopes.

Step 4: Verify Webhook Signatures (HMAC-SHA256)

Klaviyo signs each webhook payload with your signing secret. Recompute the

HMAC-SHA256 digest over the raw body and compare with crypto.timingSafeEqual

to defeat timing attacks; reject anything that does not match with 401.


const expected = crypto.createHmac('sha256', secret)
  .update(rawBody).digest('base64');
return crypto.timingSafeEqual(Buffer.from(signature), Buffer.from(expected));

Full verifier plus the Express raw-body middleware that returns

401 Invalid signature:

implementation.md → Webhook Signature Verification

and Express Webhook Middleware.

Step 5: Rotate Keys with Zero Downtime

Rotate private keys on a schedule (quarterly) or immediately on suspected leak:

generate a replacement with identical scopes, deploy it to the secret store,

verify with a curl against /api/accounts/, then revoke the old key and watch

logs for 401s. Full five-step runbook with per-platform commands:

implementation.md → API Key Rotation Procedure.

Security Checklist

  • [ ] Private API keys stored in environment variables / secret manager
  • [ ] .env files in .gitignore
  • [ ] Different API keys per environment (dev/staging/prod)
  • [ ] Minimal scopes per environment
  • [ ] Webhook signatures verified with HMAC-SHA256
  • [ ] API key rotation scheduled (quarterly recommended)
  • [ ] No private keys in client-side code
  • [ ] CI/CD uses read-only key for tests
  • [ ] Git history scanned for leaked keys (git log -p | grep pk_)

Error Handling

Security Issue Detection Mitigation
Leaked private key Git scanning, trufflehog Revoke immediately, rotate
Excessive scopes Scope audit Reduce to minimum required
Missing webhook verification Code review Add HMAC check
Key not rotated Age > 90 days Schedule rotation
401s after rotation Log monitoring Verify all services updated

Output

Applying this skill produces a hardened Klaviyo integration:

  • A git-ignored .env plus a src/config/klaviyo.ts loader that fails fast on a

missing private key.

  • Environment-scoped API keys (dev/staging/prod/CI) each holding minimum scopes.
  • A webhook endpoint that returns 200 { "received": true } only for payloads

whose HMAC-SHA256 signature verifies, and 401 { "error": "Invalid signature" }

for everything else.

  • A documented, zero-downtime rotation runbook and a completed security checklist.

Examples

Three worked scenarios — validated config loader, rejecting a forged webhook, and

zero-downtime key rotation — with inputs and expected results are in

examples.md. Quick sketch of the webhook case:


POST /webhooks/klaviyo  (tampered body, original signature)
  → verifyKlaviyoWebhookSignature() recomputes HMAC → mismatch
  → 401 { "error": "Invalid signature" }, logged as rejected

See examples.md for the full walkthrough of each.

Resources

Next Steps

For production hardening beyond secrets — rate limits, monitoring, and deploy

gates — see the klaviyo-prod-checklist skill in this pack.

Ready to use klaviyo-pack?