fetching data on the client (like supabase)
what's the "best practice" for fetching data that needs to be on the client? i'm looking at migrating from supabase, so all of the data fetching that i have right now would need to change completely - i have a lot of data fetching on the client with swr hooks + usequeries fetching data from supabase, so i'm thinking if this is the right approach to go with in the future or no
as in is the supabase approach (fetching from client) "better" and transferrable to neon in any way? with rls setup (which i have) it seems like it should be fine but i don't know
or should i migrate to fetching data from the server via actions etc? would require me to rewrite pretty much everything to swr / tanstack query, but is it overall the "better" approach long term? i'm kind of conflicted here since normally fetching db on the client is a nono but with RLS it seems.. more acceptable?
33 Replies
homely-rose•8mo ago
Take a look at my Tanstack hooks
homely-rose•8mo ago
GitHub
GitHub - daveyplate/neon-drizzle-tanstack: Use Drizzle from the fro...
Use Drizzle from the front end using Tanstack Query hooks, secured with Neon RLS - daveyplate/neon-drizzle-tanstack
homely-rose•8mo ago
I'm working on the readme and documentation right now, and an SWR port in the future
Fetching dynamic data on the client, in my opinion, is the future for sure. Supabase is pretty risky due to having no rate limiting, and they intentionally do this to surge your costs. Neon is working on their rate limiter.
I use a Next.js middleware rewrite as a proxy to the Neon serverless HTTP endpoint, and route all my client side fetches through that rewrite, which just updates the JWT with the appropriate "aud" claim then rewrites it to Neon's HTTP endpoint
This allows me to use Vercel firewall as a rate limiter (super low latency)
But you could also use an LRU cache or Upstash as a rate limiter for a Neon HTTP proxy in any other platform or host
Hopefully Neon officially releases rate limiting soon so we can just hit the serverless endpoint directly without any concerns
But yea Supabase was already extremely unsafe and has no plans to fix it
All it takes is 1 malicious actor with minimal coding knowledge to skyrocket your supabase costs by running a loop on your Postgrest or sending infinite Realtime messages in your public channel
rival-blackOP•8mo ago
wtf that's crazy, i had no idea - links to discussion one and two for anyone interested
the query allowlist seems like a nice thing, would probably need to be a build thing though. still, very cool
why do you have a proxy that rewrites the aud claim? wouldn't it make sense to set that on the client itself? don't think there would be a way to spoof it tbh - or are you using it as the rate limiter mainly? if so that makes sense, probably wouldn't have it on vercel though due to pricing
the fact that this isn't well known is actually insane - i've had annoying experiences with supabase (schema generation for json isn't overridable etc) but never something this annoying
from what i've seen in the other channel https://discord.com/channels/1176467419317940276/1303805647816757339/1328125006043021342 you're changing the aud to neon - won't that disable RLS (i might be wrong and the user key might be deeper in the jwt)
overall, what's the difference between using these hooks and just putting the query itself into the tanstack fetcher? i see you have stuff like
getFirst("books")
which fetches from the books
table - why this way and not just fetching with tanstackhomely-rose•8mo ago
It's just a more simple way for me to write my requests.
If I want books, I can just say useFindMany("books")
It would work just fine to write a custom Tanstack everywhere
rival-blackOP•8mo ago
makes sense, just wondering what are the limitations around this
homely-rose•8mo ago
Just runs Drizzle. As for the aud claim, I do that so that only requests going through my proxy are allowed
My middleware just takes the Bearer and appends aud: "neon" to it
This way no one can query the DB unless it goes through that rate limiter
Once Neon is done with theirs, I can skip this step and 0$ cost thru vercel
Since it'll just hit neon directly from react
rival-blackOP•8mo ago
makes sense i think
homely-rose•8mo ago
I don't want the client to have a JWT that can hit the DB directly cuz they could go around the rate limiter
But the front end code is the same, Drizzle queries from the front end, just sets a different fetchEndpoint as the rate limiter proxy
rival-blackOP•8mo ago
is there any estimate on the neon limiter? i know they don't want to build it wrong (which makes sense) but if it's in the terms of weeks / months etc
homely-rose•8mo ago
Simple switch to turn it off when Neon rate limiter is ready without having to rewrite much
TBH I don't know
All I know is they have written it in their docs that they are working on it
rival-blackOP•8mo ago
also most things make sense but won't stuff like drop database be prevented by RLS? https://discord.com/channels/1176467419317940276/1303805647816757339/1328136418786021416
homely-rose•8mo ago
I like the Vercel firewall in the meantime because it's really fast
Yes
You have to GRANT drop to authenticated
for that to work
you use GRANT select to authenticated then RLS to secure it
GRANT handles what operations and columns are allowed (CLS)
rival-blackOP•8mo ago
yeah so that won't be necessary no unless you grant that permission.. which sounds like a bad idea
homely-rose•8mo ago
then RLS handles what where statements and conditions for the data etc
rival-blackOP•8mo ago
haven't experimented with CLS, supabase abandoned it iirc
homely-rose•8mo ago
Yea definitely don't grant DROP
CLS is just a grant for selecting specific columns
GRANT select (id, name) from users to authenticated for example
won't let them select password
I haven't set up the CLS yet I'm going to test it out, when I used supabase I just had a separate profiles table and replicated names and usernames there
rival-blackOP•8mo ago
alr alr sounds nice
yeah have that setup with triggers too
homely-rose•8mo ago
Yea if I can't get CLS to play nice with my hooks as I have them then I'll probably just keep auth tables admin only
I'm using Better Auth
rival-blackOP•8mo ago
makes sense. i might go with workos auth. haven't checked out better-auth yet 🤔
homely-rose•8mo ago
It could work idk, I use better-auth to own all the auth data in my Neon db
homely-rose•8mo ago
I built a shadcn UI package for better auth https://github.com/daveyplate/better-auth-ui and a tanstack query package for the JWT plugin
GitHub
GitHub - daveyplate/better-auth-ui: Premade shadcn better-auth card...
Premade shadcn better-auth cards & forms. Contribute to daveyplate/better-auth-ui development by creating an account on GitHub.
rival-blackOP•8mo ago
hmm. selfhosting auth makes sense for that reason, had issues with supabase auth though so don't want to deal with the same issues myself. on the other hand, looking at what they do i'm not sure if they might be doing it the wrong way
homely-rose•8mo ago
I don't trust supabase
tbh
I told them about the security hole in realtime months ago and they never addressed it
Seems intentionally abusable
rival-blackOP•8mo ago
now i don't either. felt weird from the start, no presigning s3 URLs etc. the abuse vector is very large and there are no "defaults" for stuff like this
homely-rose•8mo ago
They told me they could disable realtime on the backend for my entire project
But like. They force every single project anyone creates to have realtime accessible
rival-blackOP•8mo ago
i don't have a usecase for realtime. the only thing i had it for was streaming updates from the users table on subscription changes + website currency changes, but that was it. tanstack query can literally do the same and better
homely-rose•8mo ago
And yea their docs encourage using Postgrest from the client with no protection
So most ppl using it are open to attacks that will cost $$ and make them profit
rival-blackOP•8mo ago
wdym by "no protection" here
homely-rose•8mo ago
they don't have any ratelimiting
on postgrest api
infinite egress with a simple js loop
rival-blackOP•8mo ago
there aren't any rate limit options on supabase itself
homely-rose•8mo ago
not for their rest api
aka supabase-js
rival-blackOP•8mo ago
which is the way everyone fetches data - there's a default limit of 50k rows returned but like bro