Closed henry2man closed 1 year ago
As a workaround, you can try to do Supabase.instance.client.rest.setAuth(...).from(...)...
.
As a workaround, you can try to do
Supabase.instance.client.rest.setAuth(...).from(...)...
.
@bdlukaa I didn't know you were here too! 😊 Thanks, I'll try it and see if it works...
I've been trying this to work but there is something missing and/or broken.
With this snippet:
print(await client.rest.setAuth(
null,
).from('rls_enabled_table').select());
print(await client.rest.setAuth(
"xxx.yourcustomjwt.ssss",
).from('rls_enabled_table').select());
And this policy:
I'm sure the custom jwt is valid because Supabase is accepting it (I made a mistake setting the signing key and the service returned a 401
error code). The snippet execution returns always an empty array. It only returns data in both calls if I disable RLS for the table.
The token payload is this:
{
"iss": "https://example.com",
"iat": 1684481355,
"nbf": 1684481355,
"exp": 1685086155,
"data": {
"user": {
"id": "xxxx"
}
}
}
Got it 🚀! This is the workaround (at least for now):
Function name: active_user
Schema: public
Definition:
DECLARE
_user_id bigint;
BEGIN
_user_id := (current_setting('request.jwt.claims', true)::json->'data'->'user'->>'id')::bigint;
RETURN EXISTS (
SELECT 1 FROM "public"."users"
WHERE id = _user_id AND enabled = true
);
EXCEPTION WHEN others THEN
RETURN false;
END;
setAuth(jwt)
for each call you need to make (ideally this should be set only once after user login...)With this code, using JWT tokens generated with Supabase secret will give you RLS enabled with custom authentication.
Another possible workaround that can be applied only once until a proper API is added:
Supabase.instance.client.headers['Authorization'] = "Bearer $jwt";
In an internal conversation @bdlukaa recommended me to use setAuth()
method on each call.
But I've double checked source code and, actually, I think that setting headers
in SupabaseClient
seems a better option because they apply not only for PostgresClient, but also to functions, storage, realtime...
If Supabase ensures that setting headers
will be always an override of any other possible header, this could be the safest method. In this was the case, we may add some clarification / documentation at least in source code
and/or, even better, in docs.
What do you think?
How would one accomplish this using the javascript sdk?
How would one accomplish this using the javascript sdk?
In the original article, the author said this:
Call
setAuth()
from the client When making calls to the Supabase API, make sure to call setAuth using the JWT from step 2 to make calls as the user.Using the
js-cookie
package (imported as Cookies):
supabase.auth.setAuth(Cookies.get("mytoken"))
NOTE: in this case a cookie is used to store the token, but this could change in other platforms.
Interesting, it looks that setAuth()
were removed from current goTrue client implementation:
https://github.com/supabase/gotrue-js/blob/master/src/GoTrueClient.ts
But it was present on previous versions:
Interesting, it looks that
setAuth()
were removed from current goTrue client implementation:
Confirmed: https://github.com/supabase/gotrue-js/pull/340
I have to read the PR well because there was a lot of controversy when removing this method
https://github.com/supabase/supabase-js/issues/553 https://github.com/supabase/gotrue-js/issues/701 https://supabase.com/docs/guides/realtime/extensions/postgres-changes#custom-tokens
TL;DR: Two approaches are discussed: per request custom client vs one time "signInWithToken
"
Ideally I think we should have a common solution between clients in order to have some coherence between SDKs. @bdlukaa @taylorjdawson can you ask Javascript folks?
We could survive with workarounds...
Looking through the JS code the access_code
from the session gets passed to the same headers as the original setAuth
method did. However, you cannot simply set the access_code
as you also have to set some refresh_token
this is where I am blocked
const { data: result, error } = await supabase.auth.setSession({
access_token: "",
refresh_token: ""
})
``
@taylorjdawson It would be great if you could open an issue on supabase-js repo and discuss this there!
@henry2man Yup, using the heasers setter is the way to go for customer JWT! Note that you are responsible for refreshing the JWT by yourself.
PR is always welcome if you want to add any comments to the SDK!
And this policy:
- table: public.rls_enabled_table
- PERMISSIVE TO authenticated
- USING (true)
@dshukertjr There is one point that is still unresolved.
With a custom token (using headers for now) I'm able to pass Supabase security controls if I pass custom tokens signed with the same secret as Supabase.
BUT when I try to implement RLS policies, I'm not able to get the authenticated
role in Postgres. I don't think this is expected in any manner.
Do tokens need any special payload in order get that role? If this is the case we need to add more context and docs in order to use custom authentication.
Please review my previous experiments:
@henry2man The role comes from the role
property of the JWT.
Here is a sample JWT provided by Supabase auth.
{
"aud": "authenticated",
"exp": 1615824388,
"sub": "0334744a-f2a2-4aba-8c8a-6e748f62a172",
"email": "d.l.solove@gmail.com",
"app_metadata": {
"provider": "email"
},
"user_metadata": null,
"role": "authenticated"
}
You can read more about it in our auth deep dive guide here.
@dshukertjr Thanks, this all makes sense now.
Is your feature request related to a problem? Please describe. In our project the authentication must be managed by a third party service. We want to enable RLS and use our own tokens with custom policies in order to fetch data, so we need to use a custom JWT in order to access Supabase.
We was trying to reproduce this article (https://medium.com/@gracew/using-supabase-rls-with-a-custom-auth-provider-b31564172d5d) but we don't find the apropiate API. In a nutshell:
supabase.auth.setAuth()
(or Dart/Flutter equivalent API) from the client: When making calls to the Supabase API, it's necessary to call setAuth using the JWT from step 2 to make calls as the user.Describe the solution you'd like
I want to set my custom session JWT in Supabase, so I can implement custom RLS policies. I want to do it only once (during login process).
Ideally we should have a public method API for setting our custom token into
auth.currentSession.accessToken
, so_getAuthHeaders()
will take it into consideration (so no header "override" will be needed):https://github.com/supabase/supabase-flutter/blob/0b7b1c6d0a84047de5dc3f295c3e1c18ff61dd1d/packages/supabase/lib/src/supabase_client.dart#L287-L295
Describe alternatives you've considered
N/A, the external Auth provider is a requisite. We didn't found an alternative in current APIEDIT: @bdlukaa contributed a possible workaround:
EDIT2: HERE is a fully working workaround: https://github.com/supabase/supabase-flutter/issues/479#issuecomment-1559170692
EDIT3: Another possible workaround that can be applied only once until a proper API is added:
Additional context
https://github.com/supabase/supabase-flutter/issues/479#issuecomment-1559117327 https://medium.com/@gracew/using-supabase-rls-with-a-custom-auth-provider-b31564172d5d https://github.com/supabase/supabase-js/issues/553 https://github.com/supabase/gotrue-js/issues/701 https://supabase.com/docs/guides/realtime/extensions/postgres-changes#custom-tokens