-
Notifications
You must be signed in to change notification settings - Fork 0
Open
Milestone
Description
The core problem (very clear)
self.supabase.get_user(token)- Every WebSocket connection → HTTP call to Supabase
- WebSockets reconnect often
- Latency + rate limits + random failures
- Completely unnecessary
Supabase already gave you a JWT.
Your job is to verify it, not ask Supabase again.
The correct mental model
Supabase Auth = JWT issuer
Django = JWT verifier
Once the client has a JWT:
- You never call Supabase again for auth
- You verify the token locally
- You trust cryptography, not network calls
What Supabase JWTs contain (important)
Supabase access tokens are standard JWTs with:
sub→ Supabase user ID (UUID)emailroleaud = "authenticated"- Signed with SUPABASE_JWT_SECRET
That’s all you need.
the FIX
SUPABASE_JWT_SECRET=your-supabase-jwt-secret(From Supabase → Project Settings → API → JWT Secret)
Channels middleware (correct)
# orchard/middleware/channels.py
from urllib.parse import parse_qs
import jwt
from django.conf import settings
from channels.db import database_sync_to_async
@database_sync_to_async
def get_or_create_user(payload):
from users.models import User
user, _ = User.objects.get_or_create(
supabase_id=payload["sub"],
defaults={
"email": payload.get("email", ""),
},
)
return user
class SupabaseChannelsAuthMiddleware:
def __init__(self, app):
self.app = app
async def __call__(self, scope, receive, send):
from django.contrib.auth.models import AnonymousUser
query_string = scope.get("query_string", b"").decode()
token = parse_qs(query_string).get("token", [None])[0]
if not token:
scope["user"] = AnonymousUser()
return await self.app(scope, receive, send)
try:
payload = jwt.decode(
token,
settings.SUPABASE_JWT_SECRET,
algorithms=["HS256"],
audience="authenticated",
)
scope["user"] = await get_or_create_user(payload)
except jwt.PyJWTError:
scope["user"] = AnonymousUser()
return await self.app(scope, receive, send)✅ No network
✅ No Supabase client
✅ O(1) speed
✅ Cryptographically secure
The backend never asks the auth provider:
“Hey, is this token valid?”
It already knows — because it has the secret.
What about token refresh?
Not your problem on the backend.
Flow:
- Client refreshes token via Supabase SDK
- Sends new token
- Backend verifies like always
Backend stays stateless 👍
What you should delete from your code
❌ In Channels:
SupabaseService()
self.supabase.get_user(token)❌ Any HTTP call to Supabase for auth
❌ Storing Supabase session server-side
Final checklist
- No Supabase SDK usage in Channels auth
- JWT verified using
jwt.decode -
SUPABASE_JWT_SECRETpresent - User fetched/created using
payload["sub"] - No network calls during WebSocket connect
If all are true → you fixed it properly.
Reactions are currently unavailable
Metadata
Metadata
Assignees
Labels
No labels