@intentsolutionsio/supabase-pack 1.0.0 → 1.0.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (133) hide show
  1. package/LICENSE +1 -1
  2. package/README.md +73 -47
  3. package/package.json +4 -4
  4. package/skills/supabase-advanced-troubleshooting/SKILL.md +404 -200
  5. package/skills/supabase-advanced-troubleshooting/references/errors.md +11 -0
  6. package/skills/supabase-advanced-troubleshooting/references/evidence-collection-framework.md +34 -0
  7. package/skills/supabase-advanced-troubleshooting/references/examples.md +11 -0
  8. package/skills/supabase-advanced-troubleshooting/references/rls-edge-functions-realtime.md +363 -0
  9. package/skills/supabase-advanced-troubleshooting/references/systematic-isolation.md +56 -0
  10. package/skills/supabase-advanced-troubleshooting/references/timing-analysis.md +35 -0
  11. package/skills/supabase-architecture-variants/SKILL.md +395 -216
  12. package/skills/supabase-architecture-variants/references/errors.md +11 -0
  13. package/skills/supabase-architecture-variants/references/examples.md +12 -0
  14. package/skills/supabase-architecture-variants/references/serverless-and-multi-tenant.md +251 -0
  15. package/skills/supabase-architecture-variants/references/variant-a-monolith-(simple).md +44 -0
  16. package/skills/supabase-architecture-variants/references/variant-b-service-layer-(moderate).md +72 -0
  17. package/skills/supabase-architecture-variants/references/variant-c-microservice-(complex).md +81 -0
  18. package/skills/supabase-auth-storage-realtime-core/SKILL.md +471 -37
  19. package/skills/supabase-ci-integration/SKILL.md +315 -67
  20. package/skills/supabase-ci-integration/references/errors.md +10 -0
  21. package/skills/supabase-ci-integration/references/examples.md +36 -0
  22. package/skills/supabase-ci-integration/references/implementation.md +54 -0
  23. package/skills/supabase-common-errors/SKILL.md +320 -62
  24. package/skills/supabase-common-errors/references/errors.md +53 -0
  25. package/skills/supabase-common-errors/references/examples.md +23 -0
  26. package/skills/supabase-cost-tuning/SKILL.md +365 -131
  27. package/skills/supabase-cost-tuning/references/cost-estimation.md +34 -0
  28. package/skills/supabase-cost-tuning/references/cost-reduction-strategies.md +40 -0
  29. package/skills/supabase-cost-tuning/references/errors.md +11 -0
  30. package/skills/supabase-cost-tuning/references/examples.md +15 -0
  31. package/skills/supabase-data-handling/SKILL.md +378 -145
  32. package/skills/supabase-data-handling/references/errors.md +11 -0
  33. package/skills/supabase-data-handling/references/examples.md +27 -0
  34. package/skills/supabase-data-handling/references/implementation.md +223 -0
  35. package/skills/supabase-data-handling/references/retention-and-backup.md +221 -0
  36. package/skills/supabase-debug-bundle/SKILL.md +267 -73
  37. package/skills/supabase-debug-bundle/references/errors.md +12 -0
  38. package/skills/supabase-debug-bundle/references/examples.md +24 -0
  39. package/skills/supabase-debug-bundle/references/implementation.md +54 -0
  40. package/skills/supabase-deploy-integration/SKILL.md +258 -147
  41. package/skills/supabase-deploy-integration/references/errors.md +11 -0
  42. package/skills/supabase-deploy-integration/references/examples.md +21 -0
  43. package/skills/supabase-deploy-integration/references/google-cloud-run.md +36 -0
  44. package/skills/supabase-deploy-integration/references/vercel-deployment.md +35 -0
  45. package/skills/supabase-enterprise-rbac/SKILL.md +327 -160
  46. package/skills/supabase-enterprise-rbac/references/api-scoping-and-enforcement.md +255 -0
  47. package/skills/supabase-enterprise-rbac/references/errors.md +11 -0
  48. package/skills/supabase-enterprise-rbac/references/examples.md +12 -0
  49. package/skills/supabase-enterprise-rbac/references/role-implementation.md +33 -0
  50. package/skills/supabase-enterprise-rbac/references/sso-integration.md +35 -0
  51. package/skills/supabase-hello-world/SKILL.md +160 -54
  52. package/skills/supabase-incident-runbook/SKILL.md +453 -131
  53. package/skills/supabase-incident-runbook/references/errors.md +11 -0
  54. package/skills/supabase-incident-runbook/references/examples.md +10 -0
  55. package/skills/supabase-incident-runbook/references/immediate-actions-by-error-type.md +41 -0
  56. package/skills/supabase-install-auth/SKILL.md +186 -50
  57. package/skills/supabase-install-auth/references/examples.md +102 -0
  58. package/skills/supabase-known-pitfalls/SKILL.md +411 -241
  59. package/skills/supabase-known-pitfalls/references/errors.md +11 -0
  60. package/skills/supabase-known-pitfalls/references/examples.md +12 -0
  61. package/skills/supabase-load-scale/SKILL.md +346 -217
  62. package/skills/supabase-load-scale/references/capacity-planning.md +47 -0
  63. package/skills/supabase-load-scale/references/errors.md +11 -0
  64. package/skills/supabase-load-scale/references/examples.md +26 -0
  65. package/skills/supabase-load-scale/references/load-testing-with-k6.md +59 -0
  66. package/skills/supabase-load-scale/references/scaling-patterns.md +65 -0
  67. package/skills/supabase-load-scale/references/table-partitioning.md +263 -0
  68. package/skills/supabase-local-dev-loop/SKILL.md +272 -73
  69. package/skills/supabase-local-dev-loop/references/errors.md +11 -0
  70. package/skills/supabase-local-dev-loop/references/examples.md +21 -0
  71. package/skills/supabase-local-dev-loop/references/implementation.md +60 -0
  72. package/skills/supabase-migration-deep-dive/SKILL.md +338 -177
  73. package/skills/supabase-migration-deep-dive/references/backfill-versioning-rollback.md +258 -0
  74. package/skills/supabase-migration-deep-dive/references/errors.md +11 -0
  75. package/skills/supabase-migration-deep-dive/references/examples.md +12 -0
  76. package/skills/supabase-migration-deep-dive/references/implementation-plan.md +80 -0
  77. package/skills/supabase-migration-deep-dive/references/pre-migration-assessment.md +39 -0
  78. package/skills/supabase-multi-env-setup/SKILL.md +393 -152
  79. package/skills/supabase-multi-env-setup/references/configuration-structure.md +59 -0
  80. package/skills/supabase-multi-env-setup/references/errors.md +11 -0
  81. package/skills/supabase-multi-env-setup/references/examples.md +11 -0
  82. package/skills/supabase-observability/SKILL.md +318 -196
  83. package/skills/supabase-observability/references/alert-configuration.md +40 -0
  84. package/skills/supabase-observability/references/errors.md +11 -0
  85. package/skills/supabase-observability/references/examples.md +13 -0
  86. package/skills/supabase-observability/references/metrics-collection.md +65 -0
  87. package/skills/supabase-performance-tuning/SKILL.md +304 -160
  88. package/skills/supabase-performance-tuning/references/caching-strategy.md +49 -0
  89. package/skills/supabase-performance-tuning/references/errors.md +11 -0
  90. package/skills/supabase-performance-tuning/references/examples.md +13 -0
  91. package/skills/supabase-policy-guardrails/SKILL.md +248 -221
  92. package/skills/supabase-policy-guardrails/references/ci-cost-security.md +484 -0
  93. package/skills/supabase-policy-guardrails/references/errors.md +11 -0
  94. package/skills/supabase-policy-guardrails/references/eslint-rules.md +46 -0
  95. package/skills/supabase-policy-guardrails/references/examples.md +10 -0
  96. package/skills/supabase-prod-checklist/SKILL.md +474 -84
  97. package/skills/supabase-prod-checklist/references/errors.md +63 -0
  98. package/skills/supabase-prod-checklist/references/examples.md +153 -0
  99. package/skills/supabase-prod-checklist/references/implementation.md +113 -0
  100. package/skills/supabase-rate-limits/SKILL.md +311 -98
  101. package/skills/supabase-rate-limits/references/errors.md +11 -0
  102. package/skills/supabase-rate-limits/references/examples.md +46 -0
  103. package/skills/supabase-rate-limits/references/implementation.md +66 -0
  104. package/skills/supabase-reference-architecture/SKILL.md +249 -182
  105. package/skills/supabase-reference-architecture/references/errors.md +29 -0
  106. package/skills/supabase-reference-architecture/references/examples.md +116 -0
  107. package/skills/supabase-reference-architecture/references/key-components.md +244 -0
  108. package/skills/supabase-reference-architecture/references/project-structure.md +109 -0
  109. package/skills/supabase-reliability-patterns/SKILL.md +229 -234
  110. package/skills/supabase-reliability-patterns/references/circuit-breaker.md +36 -0
  111. package/skills/supabase-reliability-patterns/references/dead-letter-queue.md +48 -0
  112. package/skills/supabase-reliability-patterns/references/errors.md +11 -0
  113. package/skills/supabase-reliability-patterns/references/examples.md +11 -0
  114. package/skills/supabase-reliability-patterns/references/idempotency-keys.md +36 -0
  115. package/skills/supabase-reliability-patterns/references/offline-degradation-health-dualwrite.md +489 -0
  116. package/skills/supabase-schema-from-requirements/SKILL.md +373 -34
  117. package/skills/supabase-sdk-patterns/SKILL.md +388 -99
  118. package/skills/supabase-sdk-patterns/references/errors.md +11 -0
  119. package/skills/supabase-sdk-patterns/references/examples.md +45 -0
  120. package/skills/supabase-sdk-patterns/references/implementation.md +67 -0
  121. package/skills/supabase-security-basics/SKILL.md +282 -102
  122. package/skills/supabase-security-basics/references/errors.md +10 -0
  123. package/skills/supabase-security-basics/references/examples.md +70 -0
  124. package/skills/supabase-security-basics/references/implementation.md +39 -0
  125. package/skills/supabase-upgrade-migration/SKILL.md +248 -66
  126. package/skills/supabase-upgrade-migration/references/errors.md +10 -0
  127. package/skills/supabase-upgrade-migration/references/examples.md +51 -0
  128. package/skills/supabase-upgrade-migration/references/implementation.md +29 -0
  129. package/skills/supabase-webhooks-events/SKILL.md +412 -138
  130. package/skills/supabase-webhooks-events/references/errors.md +55 -0
  131. package/skills/supabase-webhooks-events/references/event-handler-pattern.md +106 -0
  132. package/skills/supabase-webhooks-events/references/examples.md +133 -0
  133. package/skills/supabase-webhooks-events/references/signature-verification.md +165 -0
@@ -1,140 +1,320 @@
1
1
  ---
2
2
  name: supabase-security-basics
3
- description: |
4
- Apply Supabase security best practices for secrets and access control.
5
- Use when securing API keys, implementing least privilege access,
6
- or auditing Supabase security configuration.
7
- Trigger with phrases like "supabase security", "supabase secrets",
8
- "secure supabase", "supabase API key security".
9
- allowed-tools: Read, Write, Grep
3
+ description: 'Apply Supabase security best practices: anon vs service_role key separation,
4
+
5
+ RLS enforcement, policy patterns, JWT verification, and API hardening.
6
+
7
+ Use when securing a Supabase project, auditing API key usage,
8
+
9
+ implementing Row Level Security, or running a production security checklist.
10
+
11
+ Trigger with phrases like "supabase security", "supabase RLS",
12
+
13
+ "secure supabase", "supabase API key", "supabase hardening",
14
+
15
+ "row level security", "service role key".
16
+
17
+ '
18
+ allowed-tools: Read, Write, Edit, Grep, Bash(supabase:*), Bash(npx supabase:*)
10
19
  version: 1.0.0
11
20
  license: MIT
12
21
  author: Jeremy Longshore <jeremy@intentsolutions.io>
22
+ tags:
23
+ - saas
24
+ - supabase
25
+ - security
26
+ - rls
27
+ - jwt
28
+ - api-keys
29
+ compatibility: Designed for Claude Code, also compatible with Codex and OpenClaw
13
30
  ---
14
-
15
31
  # Supabase Security Basics
16
32
 
17
33
  ## Overview
18
- Security best practices for Supabase API keys, tokens, and access control.
34
+
35
+ Supabase exposes a Postgres database directly to the internet via PostgREST. Every table without Row Level Security enabled is fully readable and writable by anyone with your project URL and anon key — both of which are public. This skill covers the three pillars of Supabase security: key separation (anon vs service_role), RLS policy enforcement, and API surface hardening.
19
36
 
20
37
  ## Prerequisites
21
- - Supabase SDK installed
22
- - Understanding of environment variables
23
- - Access to Supabase dashboard
38
+
39
+ - Supabase project created (local or hosted) with Dashboard access
40
+ - `@supabase/supabase-js` installed (`npm install @supabase/supabase-js`)
41
+ - `SUPABASE_URL` and `SUPABASE_ANON_KEY` environment variables configured
42
+ - Basic understanding of SQL and Postgres
24
43
 
25
44
  ## Instructions
26
45
 
27
- ### Step 1: Configure Environment Variables
28
- ```bash
29
- # .env (NEVER commit to git)
30
- SUPABASE_API_KEY=sk_live_***
31
- SUPABASE_SECRET=***
46
+ ### Step 1 Understand the Two API Keys
32
47
 
33
- # .gitignore
34
- .env
35
- .env.local
36
- .env.*.local
48
+ Supabase issues two keys per project. Confusing them is the most common security mistake:
49
+
50
+ | Key | Environment Variable | Exposed to Client? | RLS Behavior |
51
+ |-----|---------------------|-------------------|--------------|
52
+ | **Anon key** | `SUPABASE_ANON_KEY` | Yes — browser-safe | Respects all RLS policies |
53
+ | **Service role key** | `SUPABASE_SERVICE_ROLE_KEY` | **NEVER** expose | Bypasses ALL RLS |
54
+
55
+ The anon key is a JWT that PostgREST uses to determine which RLS policies apply. It is safe to include in client-side bundles — it can only access data that RLS policies explicitly allow. The service role key bypasses every RLS policy and should only ever exist in server-side code (API routes, Edge Functions, cron jobs, migration scripts).
56
+
57
+ ```typescript
58
+ // CORRECT: anon key on the client
59
+ import { createClient } from '@supabase/supabase-js'
60
+
61
+ const supabase = createClient(
62
+ process.env.NEXT_PUBLIC_SUPABASE_URL!,
63
+ process.env.NEXT_PUBLIC_SUPABASE_ANON_KEY!
64
+ )
37
65
  ```
38
66
 
39
- ### Step 2: Implement Secret Rotation
40
- ```bash
41
- # 1. Generate new key in Supabase dashboard
42
- # 2. Update environment variable
43
- export SUPABASE_API_KEY="new_key_here"
67
+ ```typescript
68
+ // CORRECT: service role key ONLY in server-side code
69
+ // e.g., app/api/admin/route.ts (Next.js server route)
70
+ import { createClient } from '@supabase/supabase-js'
44
71
 
45
- # 3. Verify new key works
46
- curl -H "Authorization: Bearer ${SUPABASE_API_KEY}" \
47
- https://api.supabase.com/health
72
+ const supabaseAdmin = createClient(
73
+ process.env.SUPABASE_URL!,
74
+ process.env.SUPABASE_SERVICE_ROLE_KEY!,
75
+ { auth: { autoRefreshToken: false, persistSession: false } }
76
+ )
77
+ ```
48
78
 
49
- # 4. Revoke old key in dashboard
79
+ ```typescript
80
+ // WRONG — service role key in client-side code
81
+ // This bypasses ALL RLS and leaks your admin key to every user
82
+ const supabase = createClient(url, process.env.NEXT_PUBLIC_SERVICE_ROLE_KEY!) // NEVER DO THIS
50
83
  ```
51
84
 
52
- ### Step 3: Apply Least Privilege
53
- | Environment | Recommended Scopes |
54
- |-------------|-------------------|
55
- | Development | `read, write` |
56
- | Staging | `read, write, admin` |
57
- | Production | `read, write` |
85
+ **Key rotation:** Regenerate keys in Dashboard > Settings > API. After rotation, update every environment variable and redeploy all services. Old keys are invalidated immediately — there is no grace period.
58
86
 
59
- ## Output
60
- - Secure API key storage
61
- - Environment-specific access controls
62
- - Audit logging enabled
87
+ ### Step 2 — Enforce Row Level Security on Every Table
63
88
 
64
- ## Error Handling
65
- | Security Issue | Detection | Mitigation |
66
- |----------------|-----------|------------|
67
- | Exposed API key | Git scanning | Rotate immediately |
68
- | Excessive scopes | Audit logs | Reduce permissions |
69
- | Missing rotation | Key age check | Schedule rotation |
89
+ Without RLS, any table in the `public` schema is fully accessible via the REST API to anyone holding the anon key. RLS is not optional — it is the primary access control layer.
70
90
 
71
- ## Examples
91
+ ```sql
92
+ -- Audit: find tables missing RLS
93
+ SELECT schemaname, tablename, rowsecurity
94
+ FROM pg_tables
95
+ WHERE schemaname = 'public'
96
+ ORDER BY tablename;
97
+
98
+ -- Enable RLS on every public table
99
+ ALTER TABLE public.users ENABLE ROW LEVEL SECURITY;
100
+ ALTER TABLE public.todos ENABLE ROW LEVEL SECURITY;
101
+ ALTER TABLE public.profiles ENABLE ROW LEVEL SECURITY;
102
+
103
+ -- CRITICAL: enabling RLS with NO policies blocks ALL access via the API.
104
+ -- You MUST add at least one policy per table per operation (SELECT, INSERT, UPDATE, DELETE).
105
+ ```
106
+
107
+ **Policy pattern — users read/write their own rows:**
108
+
109
+ ```sql
110
+ -- SELECT: user can only read their own rows
111
+ CREATE POLICY "Users read own data"
112
+ ON public.todos FOR SELECT
113
+ USING (auth.uid() = user_id);
114
+
115
+ -- INSERT: user can only insert rows for themselves
116
+ CREATE POLICY "Users insert own data"
117
+ ON public.todos FOR INSERT
118
+ WITH CHECK (auth.uid() = user_id);
119
+
120
+ -- UPDATE: user can only update their own rows
121
+ CREATE POLICY "Users update own data"
122
+ ON public.todos FOR UPDATE
123
+ USING (auth.uid() = user_id)
124
+ WITH CHECK (auth.uid() = user_id);
125
+
126
+ -- DELETE: user can only delete their own rows
127
+ CREATE POLICY "Users delete own data"
128
+ ON public.todos FOR DELETE
129
+ USING (auth.uid() = user_id);
130
+ ```
131
+
132
+ **Policy pattern — public read, authenticated write:**
133
+
134
+ ```sql
135
+ CREATE POLICY "Anyone can read posts"
136
+ ON public.posts FOR SELECT
137
+ USING (true);
138
+
139
+ CREATE POLICY "Authenticated users can insert"
140
+ ON public.posts FOR INSERT
141
+ WITH CHECK (auth.uid() IS NOT NULL);
142
+ ```
143
+
144
+ **Policy pattern — role-based access via custom JWT claims:**
145
+
146
+ ```sql
147
+ -- Admin-only policy using app_metadata
148
+ CREATE POLICY "Admins have full access"
149
+ ON public.settings FOR ALL
150
+ USING (
151
+ (auth.jwt() -> 'app_metadata' ->> 'role') = 'admin'
152
+ );
153
+ ```
154
+
155
+ To set custom claims server-side:
72
156
 
73
- ### Service Account Pattern
74
157
  ```typescript
75
- const clients = {
76
- reader: new SupabaseClient({
77
- apiKey: process.env.SUPABASE_READ_KEY,
78
- }),
79
- writer: new SupabaseClient({
80
- apiKey: process.env.SUPABASE_WRITE_KEY,
81
- }),
82
- };
158
+ // Server-side only — requires service role key
159
+ const { error } = await supabaseAdmin.auth.admin.updateUserById(userId, {
160
+ app_metadata: { role: 'admin' }
161
+ })
83
162
  ```
84
163
 
85
- ### Webhook Signature Verification
164
+ **Policy pattern organization-scoped access:**
165
+
166
+ ```sql
167
+ CREATE POLICY "Org members can read projects"
168
+ ON public.projects FOR SELECT
169
+ USING (
170
+ EXISTS (
171
+ SELECT 1 FROM public.members
172
+ WHERE members.organization_id = projects.organization_id
173
+ AND members.user_id = auth.uid()
174
+ )
175
+ );
176
+ ```
177
+
178
+ **Key distinction — USING vs WITH CHECK:**
179
+
180
+ - `USING (expr)` — filters which existing rows the user can see (SELECT, UPDATE, DELETE)
181
+ - `WITH CHECK (expr)` — validates new/modified row data (INSERT, UPDATE)
182
+ - For UPDATE, you need both: USING controls which rows can be targeted, WITH CHECK controls what the new values can be
183
+
184
+ ### Step 3 — Harden the API Surface
185
+
186
+ **JWT verification:** Supabase verifies JWTs server-side automatically. The `auth.uid()` function in RLS policies extracts the authenticated user's ID from the verified JWT. You do not need to verify tokens manually in RLS policies — Supabase handles this.
187
+
188
+ **SQL injection prevention:** The Supabase JS SDK uses parameterized queries internally. Never build raw SQL strings from user input — always use the SDK query builder:
189
+
86
190
  ```typescript
87
- import crypto from 'crypto';
88
-
89
- function verifyWebhookSignature(
90
- payload: string, signature: string, secret: string
91
- ): boolean {
92
- const expected = crypto.createHmac('sha256', secret).update(payload).digest('hex');
93
- return crypto.timingSafeEqual(Buffer.from(signature), Buffer.from(expected));
94
- }
191
+ // SAFE: SDK parameterizes automatically
192
+ const { data } = await supabase
193
+ .from('posts')
194
+ .select('*')
195
+ .eq('author_id', userId)
196
+ .ilike('title', `%${searchTerm}%`)
197
+
198
+ // DANGEROUS: raw SQL with string interpolation
199
+ // Only use supabase.rpc() with parameterized functions, never template literals
200
+ ```
201
+
202
+ **Network restrictions:** Restrict direct database connections to known IP ranges in Dashboard > Settings > Database > Network Restrictions. This does not affect the REST API (which goes through PostgREST) but protects direct Postgres connections.
203
+
204
+ **CORS configuration:** Configure allowed origins per project in Dashboard > Settings > API > CORS. Default allows all origins (`*`) — restrict to your domains in production.
205
+
206
+ **Disable unused auth providers:** Dashboard > Authentication > Providers. Disable any provider you are not actively using (email, phone, Google, GitHub, etc.) to reduce attack surface.
207
+
208
+ **SSL enforcement:** Dashboard > Settings > Database > SSL Configuration. Enforce SSL for all direct database connections.
209
+
210
+ **Statement timeouts:** Prevent long-running queries from exhausting database resources:
211
+
212
+ ```sql
213
+ ALTER ROLE authenticated SET statement_timeout = '10s';
214
+ ALTER ROLE anon SET statement_timeout = '5s';
215
+ ```
216
+
217
+ **Revoke default schema grants (verify only):**
218
+
219
+ ```sql
220
+ -- Supabase handles this by default, but verify:
221
+ -- anon and authenticated roles should only access data through RLS policies
222
+ SELECT grantee, privilege_type, table_name
223
+ FROM information_schema.role_table_grants
224
+ WHERE table_schema = 'public'
225
+ AND grantee IN ('anon', 'authenticated')
226
+ ORDER BY table_name, grantee;
227
+ ```
228
+
229
+ ## Output
230
+
231
+ After completing these steps you will have:
232
+
233
+ - Anon key used exclusively in client-side code, service role key restricted to server-side
234
+ - RLS enabled on every public table with explicit policies per operation
235
+ - Custom JWT claims configured for role-based access patterns
236
+ - Network restrictions, CORS, SSL, and statement timeouts hardened
237
+ - Unused auth providers disabled
238
+
239
+ ### Security Audit Checklist
240
+
241
+ - [ ] RLS enabled on ALL public tables (`SELECT rowsecurity FROM pg_tables WHERE schemaname='public'`)
242
+ - [ ] Every table has at least one RLS policy per needed operation
243
+ - [ ] Service role key is NOT in any client-side or `NEXT_PUBLIC_*` environment variables
244
+ - [ ] `.env` files are in `.gitignore`
245
+ - [ ] Email confirmation enabled (Dashboard > Authentication > Settings)
246
+ - [ ] OAuth redirect URLs restricted to your domains
247
+ - [ ] Unused auth providers disabled
248
+ - [ ] SSL enforcement enabled (Dashboard > Database > SSL)
249
+ - [ ] Database password changed from default
250
+ - [ ] Network restrictions configured for direct DB connections
251
+ - [ ] `statement_timeout` set for `authenticated` and `anon` roles
252
+ - [ ] MFA enabled for sensitive user operations
253
+ - [ ] Point-in-time recovery (PITR) enabled for production
254
+ - [ ] API keys rotated after any suspected exposure
255
+
256
+ ## Error Handling
257
+
258
+ | Error | Cause | Solution |
259
+ |-------|-------|----------|
260
+ | `42501: new row violates row-level security policy` | RLS policy missing or `WITH CHECK` condition fails | Add or fix the RLS policy for that operation; verify `auth.uid()` matches the row's user column |
261
+ | Query returns empty `data` with no error | RLS `USING` clause filters out all rows | Verify `auth.uid()` in the policy matches the authenticated user; check JWT claims |
262
+ | `PGRST301: JWSError` | Invalid or expired JWT token | Re-authenticate the user; verify `SUPABASE_ANON_KEY` matches the project |
263
+ | `PGRST302: anonymous access disabled` | Anon key not provided in client init | Pass the anon key to `createClient()`; check environment variable is set |
264
+ | `permission denied for table X` | RLS enabled but no matching policy | Create a policy for the specific operation (SELECT/INSERT/UPDATE/DELETE) |
265
+ | `Could not find the function auth.uid()` | Running SQL outside PostgREST context | `auth.uid()` only works in RLS policies evaluated by PostgREST; use explicit user IDs in migrations |
266
+
267
+ ## Examples
268
+
269
+ **Minimal secure setup for a new table:**
270
+
271
+ ```sql
272
+ -- 1. Create table
273
+ CREATE TABLE public.notes (
274
+ id UUID DEFAULT gen_random_uuid() PRIMARY KEY,
275
+ user_id UUID REFERENCES auth.users(id) NOT NULL DEFAULT auth.uid(),
276
+ content TEXT NOT NULL,
277
+ created_at TIMESTAMPTZ DEFAULT now()
278
+ );
279
+
280
+ -- 2. Enable RLS immediately
281
+ ALTER TABLE public.notes ENABLE ROW LEVEL SECURITY;
282
+
283
+ -- 3. Add policies
284
+ CREATE POLICY "Users manage own notes" ON public.notes
285
+ FOR ALL USING (auth.uid() = user_id)
286
+ WITH CHECK (auth.uid() = user_id);
95
287
  ```
96
288
 
97
- ### Security Checklist
98
- - [ ] API keys in environment variables
99
- - [ ] `.env` files in `.gitignore`
100
- - [ ] Different keys for dev/staging/prod
101
- - [ ] Minimal scopes per environment
102
- - [ ] Webhook signatures validated
103
- - [ ] Audit logging enabled
289
+ **Client-side query (anon key — RLS enforced):**
104
290
 
105
- ### Audit Logging
106
291
  ```typescript
107
- interface AuditEntry {
108
- timestamp: Date;
109
- action: string;
110
- userId: string;
111
- resource: string;
112
- result: 'success' | 'failure';
113
- metadata?: Record<string, any>;
114
- }
115
-
116
- async function auditLog(entry: Omit<AuditEntry, 'timestamp'>): Promise<void> {
117
- const log: AuditEntry = { ...entry, timestamp: new Date() };
118
-
119
- // Log to Supabase analytics
120
- await supabaseClient.track('audit', log);
121
-
122
- // Also log locally for compliance
123
- console.log('[AUDIT]', JSON.stringify(log));
124
- }
125
-
126
- // Usage
127
- await auditLog({
128
- action: 'supabase.api.call',
129
- userId: currentUser.id,
130
- resource: '/v1/resource',
131
- result: 'success',
132
- });
292
+ import { createClient } from '@supabase/supabase-js'
293
+
294
+ const supabase = createClient(
295
+ process.env.NEXT_PUBLIC_SUPABASE_URL!,
296
+ process.env.NEXT_PUBLIC_SUPABASE_ANON_KEY!
297
+ )
298
+
299
+ // This only returns notes belonging to the authenticated user
300
+ // because the RLS policy filters by auth.uid()
301
+ const { data: notes, error } = await supabase
302
+ .from('notes')
303
+ .select('*')
304
+ .order('created_at', { ascending: false })
133
305
  ```
134
306
 
135
307
  ## Resources
136
- - [Supabase Security Guide](https://supabase.com/docs/security)
137
- - [Supabase API Scopes](https://supabase.com/docs/scopes)
308
+
309
+ - [Row Level Security Guide](https://supabase.com/docs/guides/database/postgres/row-level-security)
310
+ - [Securing Your API](https://supabase.com/docs/guides/api/securing-your-api)
311
+ - [Security Overview](https://supabase.com/docs/guides/security)
312
+ - [Production Checklist](https://supabase.com/docs/guides/deployment/going-into-prod)
313
+ - [Custom Claims & RBAC](https://supabase.com/docs/guides/auth/custom-claims-and-role-based-access-control-rbac)
314
+ - [@supabase/supabase-js Reference](https://supabase.com/docs/reference/javascript/introduction)
138
315
 
139
316
  ## Next Steps
140
- For production deployment, see `supabase-prod-checklist`.
317
+
318
+ - Apply production hardening with `supabase-prod-checklist`
319
+ - Set up auth flows with `supabase-auth-flows`
320
+ - Configure database migrations with `supabase-migrations`
@@ -0,0 +1,10 @@
1
+ # Error Handling Reference
2
+
3
+ | Security Issue | Detection | Mitigation |
4
+ |----------------|-----------|------------|
5
+ | Exposed API key | Git scanning | Rotate immediately |
6
+ | Excessive scopes | Audit logs | Reduce permissions |
7
+ | Missing rotation | Key age check | Schedule rotation |
8
+
9
+ ---
10
+ *[Tons of Skills](https://tonsofskills.com) by [Intent Solutions](https://intentsolutions.io) | [jeremylongshore.com](https://jeremylongshore.com)*
@@ -0,0 +1,70 @@
1
+ ## Examples
2
+
3
+ ### Service Account Pattern
4
+
5
+ ```typescript
6
+ const clients = {
7
+ reader: new SupabaseClient({
8
+ apiKey: process.env.SUPABASE_READ_KEY,
9
+ }),
10
+ writer: new SupabaseClient({
11
+ apiKey: process.env.SUPABASE_WRITE_KEY,
12
+ }),
13
+ };
14
+ ```
15
+
16
+ ### Webhook Signature Verification
17
+
18
+ ```typescript
19
+ import crypto from 'crypto';
20
+
21
+ function verifyWebhookSignature(
22
+ payload: string, signature: string, secret: string
23
+ ): boolean {
24
+ const expected = crypto.createHmac('sha256', secret).update(payload).digest('hex');
25
+ return crypto.timingSafeEqual(Buffer.from(signature), Buffer.from(expected));
26
+ }
27
+ ```
28
+
29
+ ### Security Checklist
30
+
31
+ - [ ] API keys in environment variables
32
+ - [ ] `.env` files in `.gitignore`
33
+ - [ ] Different keys for dev/staging/prod
34
+ - [ ] Minimal scopes per environment
35
+ - [ ] Webhook signatures validated
36
+ - [ ] Audit logging enabled
37
+
38
+ ### Audit Logging
39
+
40
+ ```typescript
41
+ interface AuditEntry {
42
+ timestamp: Date;
43
+ action: string;
44
+ userId: string;
45
+ resource: string;
46
+ result: 'success' | 'failure';
47
+ metadata?: Record<string, any>;
48
+ }
49
+
50
+ async function auditLog(entry: Omit<AuditEntry, 'timestamp'>): Promise<void> {
51
+ const log: AuditEntry = { ...entry, timestamp: new Date() };
52
+
53
+ // Log to Supabase analytics
54
+ await supabaseClient.track('audit', log);
55
+
56
+ // Also log locally for compliance
57
+ console.log('[AUDIT]', JSON.stringify(log));
58
+ }
59
+
60
+ // Usage
61
+ await auditLog({
62
+ action: 'supabase.api.call',
63
+ userId: currentUser.id,
64
+ resource: '/v1/resource',
65
+ result: 'success',
66
+ });
67
+ ```
68
+
69
+ ---
70
+ *[Tons of Skills](https://tonsofskills.com) by [Intent Solutions](https://intentsolutions.io) | [jeremylongshore.com](https://jeremylongshore.com)*
@@ -0,0 +1,39 @@
1
+ ## Implementation Guide
2
+
3
+ ### Step 1: Configure Environment Variables
4
+
5
+ ```bash
6
+ # .env (NEVER commit to git)
7
+ SUPABASE_API_KEY=sk_live_***
8
+ SUPABASE_SECRET=***
9
+
10
+ # .gitignore
11
+ .env
12
+ .env.local
13
+ .env.*.local
14
+ ```
15
+
16
+ ### Step 2: Implement Secret Rotation
17
+
18
+ ```bash
19
+ # 1. Generate new key in Supabase dashboard
20
+ # 2. Update environment variable
21
+ export SUPABASE_API_KEY="new_key_here"
22
+
23
+ # 3. Verify new key works
24
+ curl -H "Authorization: Bearer ${SUPABASE_API_KEY}" \
25
+ https://api.supabase.com/health
26
+
27
+ # 4. Revoke old key in dashboard
28
+ ```
29
+
30
+ ### Step 3: Apply Least Privilege
31
+
32
+ | Environment | Recommended Scopes |
33
+ |-------------|-------------------|
34
+ | Development | `read, write` |
35
+ | Staging | `read, write, admin` |
36
+ | Production | `read, write` |
37
+
38
+ ---
39
+ *[Tons of Skills](https://tonsofskills.com) by [Intent Solutions](https://intentsolutions.io) | [jeremylongshore.com](https://jeremylongshore.com)*