Skip to content

Improving the flow of handling sessions for better clarity due to RLS issues #915

Closed
@Mamdouh66

Description

@Mamdouh66

A new refactor? or a way to handle sessions

Describe the chore

I a normal flow (just following the docs (python api reference)) to insert some data into a table called X would kinda look like this

  1. A user would init a client
from supabase.client import AsyncClient, create_async_client

client = await create_async_client(
    settings.SUPABASE_PROJECT_URL, settings.SUPABASE_API_KEY
)
  1. Get the user
access_token = "getting-it-from-the-frontend"
user = await client.auth.get_user(jwt=access_token)
  1. inserting data into table X
response = await client.table("X").insert(data, returning="minimal").execute()

Now, if the developer has implemented RLS such as enabling insert for users based on user_id and them being authenticated
we would get this kind of error

postgrest.exceptions.APIError: {'code': '42501', 'details': None, 'hint': None, 'message': 'new row violates row-level security policy for table "X"'}

Now the main reason for that upon further investigations, is what happens in our RLS policy which looks like this

alter policy "Enable insert for users based on user_id"


on "public"."X"


to public


with check (

7
  (( SELECT auth.uid() AS uid) = user_id)

);

and what happens when inserting, kinda like the following

postgrest.exceptions.APIError: {'code': '42501', 'details': None, 'hint': None, 'message': 'new row violates row-level security policy for table "X"'}

Now the main reason for that upon further investigations, is what happens in our RLS policy which looks like this

alter policy "Enable insert for users based on user_id"


on "public"."X"


to public


with check (

7
  (( Null ) = "some-user-id"

);

now it auth.uid() happens to be null because when inserting and calling the db api the information of the user is not sent or the session idk.

now there are a hacky ways to solve it and a (right) way.

  1. is by using the set_session function.
    This function would require you to set both the access_token and refresh_token but this didn't make sense to make me to send them both from the frontend due to security purposes

  2. Using the secret key to bypass RLS policy.
    Still doesn't make sense due to security purposes.

  3. A problem with the get_session function is that it doesn't take any param and so it wouldn't give us the user's session to solve the problem

  4. the Right way is to use ClientOptions

client = await create_async_client(
    settings.SUPABASE_PROJECT_URL,
    settings.SUPABASE_API_KEY,
    options=ClientOptions(headers={"Authorization": f"Bearer {access_token}"}),
)

and the problem would go away and it would work normally, although the get_session still wouldn't work properly.

So, what is the problem.

That this problem is not well documented in the docs from a python perspective and one has to delve deep to find the proper solution.

Second, is that the get_session function would be more proper if it can take an access_token or an id or whatever to get the same session we have. it would save so much hassle and the use would make more sense.

After all, thanks for the team for their hard work maintaining this project

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions