feat: developer access permission gates webhooks/API keys/BYOK (v0.71.0)
Webhooks, self-serve API keys, and BYOK AI provider keys had zero access gating -- any logged-in user, any tier. Adds users.isDeveloper (boolean, admin-toggled in admin/users/[id] alongside role/tier), checked via a single hasDeveloperAccess() (lib/permissions.ts) so a future subscription-tier auto-grant is a one-line change there, not a redesign across call sites. requireDeveloper() (lib/api-auth.ts) wraps requireSession() with a fresh isDeveloper check (same reasoning as requireAdmin re-querying role: session.user's cookieCache can be up to 5 minutes stale) and replaces requireSession in all 8 gated routes: webhooks CRUD + deliveries + redeliver, api-keys CRUD, ai-keys CRUD. Settings UI: the sidebar hides API Keys/Webhooks nav entries for non-developers; those pages and the BYOK section of Settings -> AI show a locked notice instead of the manager component when accessed directly. Migration grandfathers in anyone who already has a webhook, API key, or BYOK key row -- ships as a new gate on existing features, not a silent lockout of active integrations. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
+4
-3
@@ -105,10 +105,11 @@ Status legend: **Exists** (fully working) · **Partial** (works but with a real
|
||||
| **Self-serve billing portal** | **Missing** | No Stripe customer portal; tier changes today only happen via direct admin edit at `/admin/users/[id]` | — |
|
||||
| Admin dashboard | Exists | 13 sections: overview, insights/analytics, users, invites, recipe moderation, reports, support, tiers, webhooks, audit logs, storage, AI config, site settings, changelog | `apps/web/app/admin/**` |
|
||||
| Feature flags (per-tier) vs feature prefs (per-user cosmetic) | Exists, two distinct systems | Flags gate 3 AI capabilities by tier; prefs let users hide 7 nav sections, no billing implication | `apps/web/lib/{feature-flags,feature-prefs}.ts` |
|
||||
| User webhooks (personal automation) | Exists | 7 events, Zapier-style | `apps/web/lib/webhooks.ts` |
|
||||
| Admin ops webhooks (site-wide) | Exists | 3 events (signup, ticket, report) | `apps/web/lib/admin-webhooks.ts` |
|
||||
| **Developer permission** (new, 2026-07-22) | Exists | A fourth, orthogonal access dimension — `users.isDeveloper`, admin-toggled in `admin/users/[id]`, gates user webhooks + self-serve API keys + BYOK. Previously all three had zero gating (any logged-in user, any tier). Existing users with a webhook/API key/BYOK key were grandfathered in by the migration. Deliberately a single `hasDeveloperAccess()` function so a future subscription-tier auto-grant is a one-line change, not a redesign. | `apps/web/lib/permissions.ts`, `apps/web/lib/api-auth.ts` (`requireDeveloper`) |
|
||||
| User webhooks (personal automation) | Exists | 7 events, Zapier-style, requires developer access | `apps/web/lib/webhooks.ts` |
|
||||
| Admin ops webhooks (site-wide) | Exists | 3 events (signup, ticket, report) — admin-only, unrelated to developer access | `apps/web/lib/admin-webhooks.ts` |
|
||||
| Support tickets ↔ Gitea two-way sync | Exists, verified real | Outbound (create/comment/close mirror to Gitea issue) + inbound (signed webhook receiver, dedup, loop-safe) | `apps/web/lib/gitea.ts`, `apps/web/app/api/webhooks/gitea/route.ts` |
|
||||
| Self-serve API keys | Exists | Up to 10 per user, scoped full/read, SHA-256 hashed at rest | `apps/web/app/api/v1/api-keys` |
|
||||
| Self-serve API keys | Exists | Up to 10 per user, scoped full/read, SHA-256 hashed at rest, requires developer access | `apps/web/app/api/v1/api-keys` |
|
||||
| Public OpenAPI spec + docs page | Exists | Scalar-rendered at `/docs`, spec at `/api/v1/openapi.json` | `apps/web/lib/openapi.ts` |
|
||||
| i18n | Partial | Only `en` and `fr` — no other locales | `apps/web/messages/*.json` |
|
||||
| 2FA | Exists | TOTP + backup codes + OTP, passwordless-account-compatible | Better Auth `twoFactor` plugin |
|
||||
|
||||
Reference in New Issue
Block a user