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.mdsource 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
configured.gitignore
Instructions
Step 1: Understand Key Security Profiles
| Key Type | Prefix | Exposure Risk | Capabilities |
|---|---|---|---|
| Project API Key | | Low (designed to be public) | Capture events, evaluate flags, identify users |
| Personal API Key | | 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 (
) used for all frontend/capture codephc_ - Personal key (
) only on server, never in frontend bundlesphx_ -
files in.env.gitignore - Separate keys per environment (dev/staging/prod)
- Scoped personal keys (not full admin for every service)
- Git pre-commit hook scanning for
keysphx_ - Key rotation documented and scheduled (quarterly)
Error Handling
| Issue | Detection | Fix |
|---|---|---|
| Personal key in git history | GitHub secret scanning alert | Rotate key immediately, revoke old one |
| Wrong key type | 401 on admin API | Use for admin, for capture |
| Overprivileged key | Audit log shows unexpected operations | Create scoped key, revoke broad one |
| Key exposed in logs | Log scrubbing finds | 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.