303 lines
23 KiB
Markdown
303 lines
23 KiB
Markdown
# Clerk JWT Fix - Visual Flow Diagram
|
|
|
|
## π΄ Problem Flow (Before Fix)
|
|
|
|
```
|
|
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
|
|
β User Registration β
|
|
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
|
|
β
|
|
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
|
|
β Clerk Sign Up (email/password) β
|
|
β β
User created in Clerk β
|
|
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
|
|
β
|
|
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
|
|
β Get Clerk Generic JWT β
|
|
β (Signed with Clerk's key) β
|
|
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
|
|
β
|
|
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
|
|
β Send JWT to Supabase β
|
|
β β Not recognized as authenticated β
|
|
β β Treated as 'anon' role β
|
|
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
|
|
β
|
|
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
|
|
β Try to INSERT profile β
|
|
β β RLS Policy requires 'authenticated' β
|
|
β β INSERT FAILED β
|
|
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
|
|
β
|
|
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
|
|
β β USER REGISTRATION BROKEN β
|
|
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
|
|
```
|
|
|
|
## β
Solution Flow (After Fix)
|
|
|
|
```
|
|
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
|
|
β User Registration β
|
|
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
|
|
β
|
|
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
|
|
β Clerk Sign Up (email/password) β
|
|
β β
User created in Clerk β
|
|
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
|
|
β
|
|
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
|
|
β Get Clerk Generic JWT β
|
|
β (Signed with Clerk's key) β
|
|
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
|
|
β
|
|
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
|
|
β Send JWT to Supabase β
|
|
β β οΈ Not recognized as authenticated β
|
|
β β Treated as 'anon' role β
|
|
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
|
|
β
|
|
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
|
|
β Try to INSERT profile β
|
|
β β
NEW RLS Policy allows 'public' role β
|
|
β β
Validates clerk_user_id + email β
|
|
β β
INSERT SUCCESS β
|
|
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
|
|
β
|
|
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
|
|
β β
USER REGISTRATION WORKS β
|
|
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
|
|
```
|
|
|
|
## π Security Validation Flow
|
|
|
|
```
|
|
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
|
|
β Profile INSERT Request β
|
|
β (anon role) β
|
|
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
|
|
β
|
|
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
|
|
β RLS Policy Check β
|
|
β "Allow profile creation with clerk_user_id" β
|
|
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
|
|
β
|
|
βββββββββββββββββββ
|
|
β clerk_user_id β
|
|
β IS NOT NULL? β
|
|
βββββββββββββββββββ
|
|
β β
|
|
YES NO
|
|
β β
|
|
β β REJECT
|
|
β
|
|
βββββββββββββββββββ
|
|
β clerk_user_id β
|
|
β <> ''? β
|
|
βββββββββββββββββββ
|
|
β β
|
|
YES NO
|
|
β β
|
|
β β REJECT
|
|
β
|
|
βββββββββββββββββββ
|
|
β email β
|
|
β IS NOT NULL? β
|
|
βββββββββββββββββββ
|
|
β β
|
|
YES NO
|
|
β β
|
|
β β REJECT
|
|
β
|
|
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
|
|
β β
ALL CHECKS PASSED β
|
|
β β
INSERT ALLOWED β
|
|
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
|
|
```
|
|
|
|
## π Profile Linking Flow
|
|
|
|
```
|
|
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
|
|
β Existing Profile (email only) β
|
|
β clerk_user_id: NULL β
|
|
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
|
|
β
|
|
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
|
|
β User Signs In with Clerk β
|
|
β (same email) β
|
|
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
|
|
β
|
|
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
|
|
β useAuth Hook Detects β
|
|
β 1. Profile exists by email β
|
|
β 2. clerk_user_id is NULL β
|
|
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
|
|
β
|
|
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
|
|
β Try to UPDATE profile β
|
|
β SET clerk_user_id = 'user_xxx' β
|
|
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
|
|
β
|
|
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
|
|
β RLS Policy Check β
|
|
β "Allow profile update with email match" β
|
|
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
|
|
β
|
|
βββββββββββββββββββ
|
|
β USING clause: β
|
|
β email NOT NULL? β
|
|
β clerk_user_id β
|
|
β IS NULL? β
|
|
βββββββββββββββββββ
|
|
β β
|
|
YES NO
|
|
β β
|
|
β β REJECT
|
|
β
|
|
βββββββββββββββββββ
|
|
β WITH CHECK: β
|
|
β clerk_user_id β
|
|
β NOT NULL after? β
|
|
βββββββββββββββββββ
|
|
β β
|
|
YES NO
|
|
β β
|
|
β β REJECT
|
|
β
|
|
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
|
|
β β
UPDATE ALLOWED β
|
|
β β
Profile Linked β
|
|
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
|
|
```
|
|
|
|
## π― JWT Template Flow (Recommended)
|
|
|
|
```
|
|
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
|
|
β Clerk Dashboard Setup β
|
|
β 1. Create JWT Template β
|
|
β 2. Name: "supabase" β
|
|
β 3. Signing Key: Supabase JWT Secret β
|
|
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
|
|
β
|
|
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
|
|
β User Signs In β
|
|
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
|
|
β
|
|
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
|
|
β getToken({ template: 'supabase' }) β
|
|
β β
JWT signed with Supabase secret β
|
|
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
|
|
β
|
|
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
|
|
β Send JWT to Supabase β
|
|
β β
Recognized as 'authenticated' role β
|
|
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
|
|
β
|
|
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
|
|
β All RLS Policies Work Normally β
|
|
β β
Full authenticated access β
|
|
β β
Better security β
|
|
β β
Standard Supabase behavior β
|
|
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
|
|
```
|
|
|
|
## π Policy Comparison
|
|
|
|
### Before Fix
|
|
```
|
|
ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
|
|
β Policy: "Authenticated users can create own profile" β
|
|
β Role: authenticated β
|
|
β Command: INSERT β
|
|
β β
|
|
β Clerk Generic JWT β anon role β
|
|
β β Policy doesn't match β
|
|
β β INSERT blocked β
|
|
ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
|
|
```
|
|
|
|
### After Fix
|
|
```
|
|
ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
|
|
β Policy: "Allow profile creation with clerk_user_id" β
|
|
β Role: public (includes anon + authenticated) β
|
|
β Command: INSERT β
|
|
β Check: clerk_user_id NOT NULL AND email NOT NULL β
|
|
β β
|
|
β Clerk Generic JWT β anon role β
|
|
β β
Policy matches (public includes anon) β
|
|
β β
Validation checks pass β
|
|
β β
INSERT allowed β
|
|
ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
|
|
```
|
|
|
|
## π Security Layers
|
|
|
|
```
|
|
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
|
|
β Layer 1: Role Check β
|
|
β β
public role (anon + authenticated) β
|
|
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
|
|
β
|
|
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
|
|
β Layer 2: clerk_user_id Validation β
|
|
β β
Must be non-null β
|
|
β β
Must be non-empty β
|
|
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
|
|
β
|
|
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
|
|
β Layer 3: email Validation β
|
|
β β
Must be non-null β
|
|
β β
Used for profile matching β
|
|
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
|
|
β
|
|
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
|
|
β Layer 4: Application Logic β
|
|
β β
Clerk authentication required β
|
|
β β
Email verified by Clerk β
|
|
β β
clerk_user_id from Clerk session β
|
|
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
|
|
β
|
|
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
|
|
β β
SECURE PROFILE CREATION β
|
|
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
|
|
```
|
|
|
|
## π Impact Analysis
|
|
|
|
### Before Fix
|
|
```
|
|
User Registration: β BROKEN
|
|
Profile Linking: β BROKEN
|
|
Security: β
TOO STRICT
|
|
User Experience: β POOR
|
|
```
|
|
|
|
### After Fix
|
|
```
|
|
User Registration: β
WORKING
|
|
Profile Linking: β
WORKING
|
|
Security: β
MAINTAINED
|
|
User Experience: β
EXCELLENT
|
|
```
|
|
|
|
### With JWT Template
|
|
```
|
|
User Registration: β
WORKING
|
|
Profile Linking: β
WORKING
|
|
Security: β
ENHANCED
|
|
User Experience: β
EXCELLENT
|
|
Supabase Features: β
FULL ACCESS
|
|
```
|
|
|
|
---
|
|
|
|
**Legend:**
|
|
- β
Working / Allowed
|
|
- β Broken / Blocked
|
|
- β οΈ Warning / Limitation
|
|
- β Flow direction
|
|
- β Next step
|