|
| 1 | +--- |
| 2 | +meta: |
| 3 | + title: How to use Row Level Security with PostgREST for Serverless SQL Databases |
| 4 | + description: This page provides the steps to use Row Level Security with PostGREST for Serverless SQL Databases |
| 5 | +content: |
| 6 | + h1: How to use Row Level Security with PostgREST for Serverless SQL Databases |
| 7 | + paragraph: This page provides the steps to use Row Level Security with PostGREST for Serverless SQL Databases |
| 8 | +tags: sql-databases serverless database row-level-security postgresql postgrest |
| 9 | +dates: |
| 10 | + validation: 2024-09-24 |
| 11 | + posted: 2024-09-24 |
| 12 | +categories: |
| 13 | + - serverless |
| 14 | +--- |
| 15 | + |
| 16 | +## Use Row Level Security with PostgREST |
| 17 | + |
| 18 | +PostgREST built-in Row Level Security based on users JWT relies either on [role impersonation](https://docs.postgrest.org/en/v12/references/auth.html#user-impersonation) or [transaction-scoped settings](https://docs.postgrest.org/en/v12/references/transactions.html#tx-settings). Due to connection pooling, Serverless SQL Database currently only support transaction-scoped settings and requires using a single PostgreSQL role for all queries (the internal `role_readwrite` in PostgreSQL). |
| 19 | + |
| 20 | +1. [Install PostgREST](https://docs.postgrest.org/en/v12/tutorials/tut0.html#step-1-install-postgresql) |
| 21 | + |
| 22 | +2. Create a `tutorial.conf` file with the following content: |
| 23 | + ``` |
| 24 | + db-uri = "postgres://[user-or-application-id]:[api-secret-key]@[database-hostname]:5432/[database-name]?sslmode=require" |
| 25 | + db-schemas = "[your database schema]" |
| 26 | + jwt-secret = "[your jwt secret]" |
| 27 | + ``` |
| 28 | + where: |
| 29 | + - `db-uri` should use credentials with an application having **ServerlessSQLDatabaseDataReadWrite** permissions (and not **ServerlessSQLDatabaseDataReadWrite** neither **ServerlessSQLDatabaseFullAccess**) |
| 30 | + - `db-schemas` is your database schema. You can use `"public"` as a default value. |
| 31 | + - `jwt-secret` can be generated using the command `openssl rand -base64 32` |
| 32 | + |
| 33 | +3. Run PostgREST: |
| 34 | + ```bash |
| 35 | + postgrest tutorial.conf |
| 36 | + ``` |
| 37 | + You can check that your are able to query your database by [generating a JWT](https://docs.postgrest.org/en/v12/tutorials/tut1.html#step-3-sign-a-token) with the payload data `{"role": "role_readwrite"}`: |
| 38 | + ```bash |
| 39 | + curl http://localhost:3000/pets \ |
| 40 | + -H "Authorization: Bearer $TOKEN" |
| 41 | + ``` |
| 42 | + where `$TOKEN` is your generated JWT. |
| 43 | + A pet list should display. |
| 44 | + |
| 45 | +4. Connect to your Serverless SQL Database with **ServerlessSQLDatabaseFullAccess** permissions, and delete the existing policy on the `pets` table: |
| 46 | + ```sql |
| 47 | + DROP POLICY pets_keeper ON pets; |
| 48 | + ``` |
| 49 | + |
| 50 | +5. Create a new policy on the `pets` table: |
| 51 | + ```sql |
| 52 | + CREATE POLICY pets_keeper ON pets TO role_readwrite |
| 53 | + USING (keeper = current_setting('request.jwt.claims', true)::json->>'user_type'); |
| 54 | + ``` |
| 55 | + This policy will use `current_settings` instead on `current_user` and thus check for additional fields contained by the JWT instead of only the `"role"` field. |
| 56 | + |
| 57 | +6. Generate a JWT with the following payload data: |
| 58 | + ```json |
| 59 | + { |
| 60 | + "role": "role_readwrite", |
| 61 | + "user_type": "role_readwrite" |
| 62 | + } |
| 63 | + ``` |
| 64 | + <Message type="tip"> |
| 65 | + In this configuration, `user_type` value from JWT will be checked against `keeper` column value in your database to authorize access. You can replace `"user_type": "role_readwrite"` by any alternative field name or value depending on your use case. However you need to keep `"role": "role_readwrite"` for any kind of users you want to authenticate through PostgREST, because alternative roles (such as `role_admin`) will already have too much privileges and be able to see any data. |
| 66 | + </Message> |
| 67 | + |
| 68 | +7. Query your database using this JWT through PostgREST: |
| 69 | + ```bash |
| 70 | + curl http://localhost:3000/pets \ |
| 71 | + -H "Authorization: Bearer $TOKEN" |
| 72 | + ``` |
| 73 | + You should only see pets with a `keeper` column value of `role_readwrite`. |
| 74 | + |
| 75 | + Your new application can now only access a specific subset of rows based on its permissions using transaction-scoped settings. |
| 76 | + |
| 77 | + <Message type="tip"> |
| 78 | + You can change your JWT payload data with `"user_type": "role_admin"` and see that only another set of rows will be displayed. You can go further by adding any additional fields or values to filter, and edit your policy to filter on a more complex set of rules. |
| 79 | + </Message> |
0 commit comments