When using a secret key for backend components, we grant them all privileges of the service_role so in most cases they have access to parts of the db they do not need to have or actually shouldn't. In my understanding this violates the principle of least privilege even if security is properly enforced in the backend components.
Adding the possibility in Project Settings -> API Keys to add a 'Service Key' (legacy service_role API key is not meant) where you can select a Postgres role. Custom roles can be selected there so we can use other roles then anon, authenticated and service_role (from the publishable/secret key) in a backend components. With the custom Postgres role we have fine control over what the backend components can access in the db.
For people interested, this is my current approach in detail:
supabase gen signing-key --algorithm ES256
supabase gen bearer-jwt --role <your_service_role> --exp 2147483647
.env.Dashboard -> Settings -> JWT Signing Keys -> Create Standby Key
b. Select Import an existing key, paste the previously generated and create.
c. Three-dot menu -> Move to previously used (Supabase will use this key just to verify, not for signing).import { createClient } from '@supabase/supabase-js'
const supabase = createClient(
process.env.SUPABASE_URL,
process.env.SUPABASE_PUBLISHABLE_KEY,
{
accessToken: () => Promise.resolve(process.env.YOUR_SERVICE_JWT),
}
)
If the JWT gets compromised, just revoke the signing key from step 4 and all JWTs signed with it will be invalid.
While this works, it doesn't feel "official" and is extra work to setup
Lasse Amonat suggests adding a feature to Supabase allowing custom API keys with selectable Postgres roles for backend components. This would enhance security by adhering to the principle of least privilege, as the current service_role grants excessive privileges. Lasse provides a workaround using Supabase CLI to generate signing keys and JWTs, but notes it feels unofficial and cumbersome.