Skip to content

Server client fed with a secret key returns a storage client that does not bypass RLS #141

@NathanAlkurdi

Description

@NathanAlkurdi

Bug report

  • I confirm this is a bug with Supabase, not with my own application.
  • I confirm I have searched the Docs, GitHub Discussions, and Discord.

Describe the bug

When the consumer initializes a supabase server client with a secret key, storage operations still require RLS, even though a secret key should bypass RLS.

To Reproduce

Steps to reproduce the behavior, please provide code snippets or a repository:

  1. Setup a supabase client with a secret key like so:
import { createServerClient } from "@supabase/ssr";
import { cookies } from "next/headers";
import { Env } from "../env";

export async function createClient() {
	const cookieStore = await cookies();

	return createServerClient(
		Env.NEXT_PUBLIC_SUPABASE_URL!,
		Env.SUPABASE_SECRET_KEY!,
		{
			cookies: {
				getAll() {
					return cookieStore.getAll();
				},
				setAll(cookiesToSet) {
					try {
						cookiesToSet.forEach(({ name, value, options }) =>
							cookieStore.set(name, value, options),
						);
					} catch {
						// The `setAll` method was called from a Server Component.
						// This can be ignored if you have middleware refreshing
						// user sessions.
					}
				},
			},
		},
	);
}
  1. Setup a public storage bucket
  2. Access the client and attempt to upload a file like so:
const { data: uploadedImageData, error: uploadedImageError } =
	await supabaseClient.storage
		.from("user_images")
		.upload(filePath, imageBuffer, {
			contentType: "image/png",
		});
  1. See error returned from upstream like so:
{"statusCode":"403","error":"Unauthorized","message":"new row violates row-level security policy"}

Expected behavior

The storage client initialized and accessible within the supabase client should allow operations to bypass RLS when a secret key is passed.

System information

  • OS: macOS Tahoe 26.0.1
  • Browser (if applies) [e.g. chrome, safari]: N/A
  • Version of @supabase/supabase-js: 2.50.0
  • Version of @supabase/ssr: 0.6.1
  • Version of Node.js: 22.14.0

Additional context

I have personally validated the client returned and utilized for this storage operation had the correct secret key under client.supabaseKey with the one under API keys in the supabase dashboard. I have only tried this with the upload operation on the storage client, but this will likely occur for the others. If I had to guess, there may not be options passed down to the underlying storage client resulting in the authorization header to not be setup as expected based on the behavior.

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't working

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions