klaviyo-security-basics
'Apply Klaviyo security best practices for API key management and access
Allowed Tools
Provided by Plugin
klaviyo-pack
Claude Code skill pack for Klaviyo (24 skills)
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
- [ ]
.envfiles 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
.envplus asrc/config/klaviyo.tsloader 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
- Authenticate API Requests
- OAuth Setup
- Webhooks API Overview
- implementation.md — full copy-paste code for every step
- examples.md — end-to-end worked scenarios
Next Steps
For production hardening beyond secrets — rate limits, monitoring, and deploy
gates — see the klaviyo-prod-checklist skill in this pack.