Open WesleyYue opened 1 year ago
Hi @WesleyYue thanks for your question.
Do you have any guidance on how to manage the number of Prisma clients? Typically, you'd have one Prisma client for the application.
I think I would still have one client per application, or maybe two (not including what Prisma would use to run its migrations using the directUrl
connection string that I would keep superuser/admin rights on).
1 - A client that was used by the application to execute queries based on behalf of a user. This would be the client that useSupabaseRowLevelSecurity
extends.
2 - I may still have some admin client that bypasses RLS for its role (this would not use useSupabaseRowLevelSecurity
and would specify a datasource url that grants more access and permissions).
Given that each Prisma client now has their own unique extension with the appropriate claims, what is the recommended pattern for managing Prisma client instances?
I don't think that would be the case that "each Prisma client now has their own unique extension with the appropriate claims" because there is a claimsFn
that would dynamically set the claims per request.
What I mean is, seen in this example:
const prisma = new PrismaClient({
datasources: { db: { url: process.env.RLS_DATABASE_URL } },
}).$extends(
useSupabaseRowLevelSecurity({
/**
* Return the decoded current user from the context
*/
claimsFn: () => context.currentUser,
/**
* Throw a RedwoodJS ForbiddenError if the policy is violated
*/
policyError: new ForbiddenError('Violates RLS.'),
})
)
The claimsFn
will get the currentUser here from context. In RedwoodJS, this object would have the necessary JWT claims for Supabase to use to authenticate and apply RLS policies.
So, this "app res-enforced client" can be used over an over for any user.
Perhaps I am not understanding your question, but beyond an app or admin Prisma client, what other clients do you envision needed in your application?
For Supabase, it is common to use their auth
functions to CHECK that the policy permissions are valid:
CREATE POLICY "Authenticated users can modify Pedals" ON "public"."Pedal"
AS PERMISSIVE FOR UPDATE
TO rls_user
USING (auth.jwt() ->> 'role' = 'authenticated')
WITH CHECK (auth.jwt() ->> 'role' = 'authenticated');
But, I guess if your policy uses "some other" check then the default claimsSetting of this client extension would not work.
It's geared to sending JWT claims so that auth.jwt()
checks can work given that Supabase check claimsSetting: 'request.jwt.claims'
and that's what's set.
I imagine you could override the default claimsSetting
.. and then yes, you would need multiple rls-enforcing clients per claimsSetting
for the type of queries you make, but for Supabase this is essentially user to always be that claimsSetting since that's how its own SDK works and what it expects.
Hope that helps!
Thanks, I think was misunderstanding how Prisma extensions worked, and I was not aware that you can extend the same base client instance without concerns for conflicts as the returned client instances from .$extends() are isolated from one another.
Hi, thanks for writing up this example. Do you have any guidance on how to manage the number of Prisma clients? Typically, you'd have one Prisma client for the application. Given that each Prisma client now has their own unique extension with the appropriate claims, what is the recommended pattern for managing Prisma client instances?