Utilizing client extension for Postgres with Prisma to activate RLS: A step-by-step guide

Recently, I attempted to implement client extension as advised on Github. My approach involved defining row level security policies in my migration.sql file:

-- Enabling Row Level Security
ALTER TABLE "User" ENABLE ROW LEVEL SECURITY;
ALTER TABLE "Company" ENABLE ROW LEVEL SECURITY;

-- Applying Row Level Security for table owners
ALTER TABLE "User" FORCE ROW LEVEL SECURITY;
ALTER TABLE "Company" FORCE ROW LEVEL SECURITY;

-- Defining row security policies
CREATE POLICY tenant_isolation_policy ON "Company" USING ("id" = current_setting('app.current_company_id', TRUE)::uuid);
CREATE POL

In addition, I have specified only two models in my schema.prisma file:

generator client {
  provider        = "prisma-client-js"
  previewFeatures = ["clientExtensions"]
}

datasource db {
  provider = "postgresql"
  url      = env("DATABASE_URL")
}

model Company {
  id    String @id @default(dbgenerated("gen_random_uuid()")) @db.Uuid
  name  String
  users User[]
}

model User {
  id        String  @id @default(dbgenerated("gen_random_uuid()")) @db.Uuid
  companyId String  @default(dbgenerated("(current_setting('app.current_company_id'::text))::uuid")) @db.Uuid
  email     String  @unique
  company   Company @relation(fields: [companyId], references: [id], onDelete: Cascade)
}

Furthermore, my script.js file contains various functions aimed at validating the functionality of RLS. Despite creating test data for both company and user tables, I am facing difficulties in restricting access to companies or users as required.

//Setting a company_id as current_company_id for RLS Validation
const setUserId = await prisma.$executeRaw`SET app.current_company_id = 'id_of_a_company';`;
// Creating a specific company with a user
await prisma.company.create({
        data: {
          name: "Company 1",
          users: {
            create: {
              email: "<a href="/cdn-cgi/l/email-protection" class="__cf_email__" data-cfemail="e693958394d7a685898b9687889fd7c885898b">[email protected]</a>",
            },
          },
        },
      });
// Attempting to query users from Company 1 as a user who should have access
    const company1Users = await prisma.user.findMany({
        where: {
        company: {
            name: "Company 1",
        },
        },
    });
    // Trying to fetch users from Company 2 as a user without access privileges
    const company2Users = await prisma.user.findMany({
        where: {
        company: {
            name: "Company 2",
        },
        },
    });

Any insights on what could be going wrong here?

Answer №1

Here are two potential reasons for the issue:

First: Ensure you are using the extended PrismaClient

It appears that in your examples, you have not shown that you are extending the original PrismaClient with the necessary data from current_settings and then utilizing that client for queries.

For instance, this is how you can configure the extended client to utilize the current_settings:

const db = new PrismaClient()
const rlsDb = db.$extends(currentCompanyRlsExtension(session.company.id))

function currentCompanyRlsExtension(companyId) {
  return Prisma.defineExtension((prisma) =>
    prisma.$extends({
      query: {
        $allModels: {
          async $allOperations({ args, query }) {
            const [, result] = await prisma.$transaction([
              prisma.$executeRaw`SELECT set_config('app.current_company_id', ${companyId}, TRUE)`,
              query(args),
            ])
            return result
          },
        },
      },
    }),
  )
}

When making database queries, ensure to use the extended client:

const companyUsers = await rlsDb.user.findMany()

Second: Confirm that you are using a database user that cannot bypass RLS

Verify that your DATABASE_URL does not employ a database user that will consistently bypass RLS. According to the PostgreSQL v16 documentation:

Superusers and roles with the BYPASSRLS attribute always skip the row security system when accessing a table. Table owners typically bypass row security as well, unless they choose to abide by row security with ALTER TABLE ... FORCE ROW LEVEL SECURITY.

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

The module 'json-stringify-safe' could not be located

Encountering an issue while executing the command - ionic serve The code was functioning properly on a different system but seems to be causing trouble for me at the moment. ...

Chart.js Axis Labels Orientation Guidelines

I am currently utilizing chart.js within an Angular 8 environment using Primeng. I am looking to customize the options for my chart as follows: For the y-axis ticks, set textDirection to 'ltr' For the x-axis ticks, set textDirection to 'rtl ...

Angular Material Table displaying real-time information

Recently, I've delved into Angular and have been experimenting with creating a dynamic table to showcase data. Currently, I have managed to get it partially working with static data. I drew inspiration from this particular example: https://stackblit ...

Syntax for nested arrow functions in TypeScript

const fetchAsyncData = (input: { value: string }): AppThunk => async (dispatch) => { try { const fetchedData = await getData({ input.value }); } catch (error) { console.log(error); } }; An error message is displayed stating "No value ...

Why use rxjs observables if they don't respond to updates?

I have an array of items that I turn into an observable using the of function. I create the observable before populating the array. However, when the array is finally populated, the callback provided to subscribe does not execute. As far as I know, th ...

Typescript may fall short in ensuring type safety for a basic reducer

I have been working on a simple reducer that uses an object to accumulate values, aiming to maximize TS inference. However, I am facing difficulties in achieving proper type safety with TypeScript. The issue arises when the empty object does not contain an ...

In TypeScript, the catch block does not get triggered

I created a custom pipe in Angular that is supposed to format passed parameters to date format. The pipe contains a try-catch block to handle any errors, but surprisingly the catch block never seems to be executed even when an invalid date is passed. impo ...

What is the correct way to construct an object in TypeScript while still taking types into account?

Hey, I'm having trouble implementing a common JavaScript pattern in TypeScript without resorting to using any to ignore the types. My goal is to write a function that constructs an object based on certain conditions and returns the correct type. Here& ...

When defining a class property in TypeScript, you can make it optional by not providing

Is there a way to make a property on a Class optional without it being undefined? In the following example, note that the Class constructor takes a type of itself (this is intentional) class Test { foo: number; bar: string; baz?: string; construc ...

Angular component name constraints - 'the selector [your component name] is not permissible'

When trying to generate a component using the Angular 6 CLI (version 6.0.7), I encountered an issue. After typing in ng g c t1-2-3-user, I received an error message stating that the selector (app-t1-2-3-user) is invalid. I wondered if there was something ...

Looking for help with setting up Nodemailer and installing it via NPM

I am currently developing a mobile application using Ionic with Angular/Typescript, and I'm in need of a front-end solution to dynamically send emails in the background to a specific email address. I tried using emailjs, but it requires JavaScript whi ...

React Native error - Numeric literals cannot be followed by identifiers directly

I encountered an issue while utilizing a data file for mapping over in a React Native component. The error message displayed is as follows: The error states: "No identifiers allowed directly after numeric literal." File processed with loaders: "../. ...

Generate a fresh array by filtering objects based on their unique IDs using Angular/Typescript

Hey there, I am receiving responses from 2 different API calls. Initially, I make a call to the first API and get the following response: The first response retrieved from the initial API call is as follows: dataName = [ { "id": "1", ...

Angular 5 Dilemma: Exporting UI Components without Locating Template

My current project involves developing UI Components that will be used in various web projects within the company. Our plan is to publish these UI components as an npm package on our local repository, and so far, the publishing process has been successful. ...

Solving the error message "Cannot find module '@angular/router/src/utils/collection' or its corresponding type declaration"

How do I troubleshoot this Error: src/app/metronic/orderByLocation/locationsByOneOrder/locationsByOneOrder.component.ts:7:25 - error TS2307: Cannot find module '@angular/router/src/utils/collection' or its corresponding type declarations.m 7 imp ...

The error message is: "Cannot access property 'up' of an undefined object within the material UI library using theme.breakpoints."

I am encountering difficulties with the export of makeStyles. Below you can find my code and configuration: import SearchField from "../SearchField"; import { TextField, Select, useMediaQuery, Grid, Button, Box, Fade } from '@material-ui/core&ap ...

Filtering an array of objects in TypeScript based on the existence of a specific property

I'm attempting to filter objects based on whether or not they have a specific property. For example: objectArray = [{a: "", b: ""}, {a: ""}] objectArray.filter( obj => "b" in obj ).forEach(obj => console. ...

Encountering a script error when upgrading to rc4 in Angular 2

After attempting to update my Angular 2 version to 2.0.0.rc.4, I encountered a script error following npm install and npm start. Please see my package.json file below "dependencies": { "@angular/common": "2.0.0-rc.4", "@angular/core": "2.0.0-rc.4", ...

What steps should I follow to set up a TypeScript project that incorporates JavaScript modules compiled from PureScript?

TL;DR I am looking to develop TypeScript typings for compiled PureScript modules and include them in my npm package. I am willing to manually maintain these typings, but I am struggling with the configuration needed in tsconfig.json (up and downstream) and ...

Steps to disable TypeScript error messages for unused variables

I encountered an issue in my Angular CLI that says: jest.config.js is part of the TypeScript compilation but it's unused. Add only entry points to the 'files' or 'include' properties in your tsconfig. Additionally, I have a few o ...