Claude-code-plugins-plus-skills posthog-security-basics

install
source · Clone the upstream repo
git clone https://github.com/jeremylongshore/claude-code-plugins-plus-skills
Claude Code · Install into ~/.claude/skills/
T=$(mktemp -d) && git clone --depth=1 https://github.com/jeremylongshore/claude-code-plugins-plus-skills "$T" && mkdir -p ~/.claude/skills && cp -r "$T/plugins/saas-packs/posthog-pack/skills/posthog-security-basics" ~/.claude/skills/jeremylongshore-claude-code-plugins-plus-skills-posthog-security-basics && rm -rf "$T"
manifest: plugins/saas-packs/posthog-pack/skills/posthog-security-basics/SKILL.md
source content

PostHog Security Basics

Overview

Secure PostHog API key management, least-privilege access, and secret rotation. PostHog has two key types with very different security profiles: the Project API Key (

phc_...
) is intentionally public and safe to include in frontend bundles, while the Personal API Key (
phx_...
) grants admin access and must never be exposed.

Prerequisites

  • PostHog account with admin access
  • Understanding of environment variable management
  • .gitignore
    configured

Instructions

Step 1: Understand Key Security Profiles

Key TypePrefixExposure RiskCapabilities
Project API Key
phc_
Low (designed to be public)Capture events, evaluate flags, identify users
Personal API Key
phx_
Critical (full admin access)CRUD flags, read persons, query insights, delete data
# .env (NEVER commit)
NEXT_PUBLIC_POSTHOG_KEY=phc_abc123   # Safe for frontend (NEXT_PUBLIC_ prefix)
POSTHOG_PERSONAL_API_KEY=phx_xyz789  # Server-only — NEVER in frontend code
POSTHOG_PROJECT_ID=12345

# .gitignore
.env
.env.local
.env.*.local

Step 2: Create Scoped Personal API Keys

set -euo pipefail
# Create a read-only key for BI dashboards
curl -X POST "https://app.posthog.com/api/personal_api_keys/" \
  -H "Authorization: Bearer $POSTHOG_PERSONAL_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "label": "bi-dashboard-readonly",
    "scopes": ["insight:read", "dashboard:read", "query:read"]
  }'

# Create a key scoped to feature flags only
curl -X POST "https://app.posthog.com/api/personal_api_keys/" \
  -H "Authorization: Bearer $POSTHOG_PERSONAL_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "label": "feature-flag-service",
    "scopes": ["feature_flag:read", "feature_flag:write"]
  }'

Step 3: Rotate Personal API Keys

set -euo pipefail
# 1. Create new key in PostHog Settings > Personal API Keys
# 2. Update secret in your deployment platform
# Vercel:
vercel env rm POSTHOG_PERSONAL_API_KEY production
vercel env add POSTHOG_PERSONAL_API_KEY production

# GitHub Actions:
gh secret set POSTHOG_PERSONAL_API_KEY --body "phx_new_key_here"

# 3. Verify new key works
curl -s "https://app.posthog.com/api/projects/" \
  -H "Authorization: Bearer $POSTHOG_PERSONAL_API_KEY" | jq '.[0].name'

# 4. Delete old key in PostHog dashboard

Step 4: Prevent Key Leaks

# Git pre-commit hook to catch PostHog personal keys
# .git/hooks/pre-commit (or use husky)
#!/bin/bash
if git diff --cached --diff-filter=ACM | grep -qE 'phx_[a-zA-Z0-9]{20,}'; then
  echo "ERROR: PostHog personal API key (phx_) detected in staged files!"
  echo "Remove it and use environment variables instead."
  exit 1
fi
# .github/secret-scanning.yml (or use GitHub's built-in secret scanning)
patterns:
  - name: PostHog Personal API Key
    regex: 'phx_[a-zA-Z0-9]{20,}'
    severity: critical

Step 5: Server-Side Key Isolation

// lib/posthog-server.ts — Personal key never leaves the server
import { PostHog } from 'posthog-node';

const posthog = new PostHog(process.env.NEXT_PUBLIC_POSTHOG_KEY!, {
  host: 'https://us.i.posthog.com',
  // personalApiKey ONLY used server-side for local flag evaluation
  personalApiKey: process.env.POSTHOG_PERSONAL_API_KEY,
});

// API routes that proxy admin operations
// Never expose the personal key to the client
export async function getFeatureFlagsForUser(userId: string) {
  return posthog.getAllFlags(userId);
}

Step 6: Audit API Key Usage

set -euo pipefail
# Check activity log for API key operations
curl "https://app.posthog.com/api/projects/$POSTHOG_PROJECT_ID/activity_log/" \
  -H "Authorization: Bearer $POSTHOG_PERSONAL_API_KEY" | \
  jq '[.results[] | select(.scope == "PersonalAPIKey") | {
    user: .user.email,
    activity: .activity,
    created_at
  }]'

Security Checklist

  • Project key (
    phc_
    ) used for all frontend/capture code
  • Personal key (
    phx_
    ) only on server, never in frontend bundles
  • .env
    files in
    .gitignore
  • Separate keys per environment (dev/staging/prod)
  • Scoped personal keys (not full admin for every service)
  • Git pre-commit hook scanning for
    phx_
    keys
  • Key rotation documented and scheduled (quarterly)

Error Handling

IssueDetectionFix
Personal key in git historyGitHub secret scanning alertRotate key immediately, revoke old one
Wrong key type401 on admin APIUse
phx_
for admin,
phc_
for capture
Overprivileged keyAudit log shows unexpected operationsCreate scoped key, revoke broad one
Key exposed in logsLog scrubbing finds
phx_
Redact logs, rotate key

Output

  • Environment-specific API key configuration
  • Scoped personal API keys for least privilege
  • Key rotation procedure
  • Git pre-commit hook for leak prevention
  • Audit log queries for key usage monitoring

Resources

Next Steps

For production deployment, see

posthog-prod-checklist
.