francesco primerano
francesco primerano

Reputation: 3

Supabase Storage & RLS: JWT Role Not Recognized, Permission Denied Errors

I am new to Supabase and trying to set up a private storage bucket where only users with an "Admin" role in their JWT can upload and manage files.

I’ve created the necessary policies, roles, and privileges in Supabase, but when I try to upload or retrieve files using the Supabase API, I keep getting authentication errors such as:

Despite my efforts, I can’t get Supabase Storage to recognize my JWT claims properly.

Here’s everything I’ve done step-by-step:

Created a Private Storage Bucket named Documents to store uploaded files.

I manually created the "Admin" role in Supabase to distinguish privileged users.

I enabled Row Level Security and added policies for the "Admin" role.

CREATE POLICY "Allow only Admins to insert files"
ON storage.objects
FOR INSERT
TO authenticated
WITH CHECK (
    ((auth.jwt() ->> 'role') = 'Admin')
    OR ((auth.jwt() -> 'app_metadata' ->> 'role') = 'Admin')
);

I generated a custom JWT that includes role: "Admin" in the app_metadata.

const jwt = require('jsonwebtoken');

exports.getSupabaseToken = (userId, email, role = 'Admin', expirationTime = '2h') => {
    return jwt.sign(
        {
            aud: "authenticated",
            sub: userId,
            email,
            app_metadata: { role },
            user_metadata: {},
            role,
        },
        process.env.SUPABASE_JWT_SECRET,
        { expiresIn: expirationTime }
    );
};

This is the decoded jwt

{
  "aud": "authenticated",
  "sub": "005f43c1-b7ad-4895-a6ba-6a26ff108d69",
  "email": "[email protected]",
  "app_metadata": {
    "role": "Admin"
  },
  "user_metadata": {},
  "role": "Admin",
  "iat": 1740258968,
  "exp": 1740345368
}

When I run in supabase:

SELECT auth.jwt();

I get NULL, which means Supabase is not recognizing the JWT from my request.

To test authentication, I tried cURL requests:

curl -X GET "https://gegsudafxipazfnenzrc.supabase.co/storage/v1/object/authenticated/Documents/ricevuta.pdf" \
-H "apikey: <SUPABASE_ANON_KEY>" \
-H "Authorization: Bearer <MY_JWT>"

Which gave me:

{
  "statusCode": "403",
  "error": "Unauthorized",
  "message": "new row violates row-level security policy"
}

Or { "code": "42501", "message": "permission denied to set role "Admin"" }

Even though the JWT has role: "Admin", Supabase does not grant the "Admin" role dynamically.

This is how I pass the token to the client:

const { createClient } = require('@supabase/supabase-js');

const supabase = createClient(process.env.SUPABASE_URL, process.env.SUPABASE_ANON_KEY, {
    global: {
        headers: {
            Authorization: `Bearer ${supabaseToken}`
        }
    }
});

I'm really stuck on this. I feel like I'm missing a key step in how Supabase reads JWT roles and applies policies. Any guidance would be amazing!

Upvotes: 0

Views: 9

Answers (0)

Related Questions