Local PostgREST returns PGRST301 (Invalid JWT parts) when createClient sb_secret/sb_publish
What I’m trying to do
- Run a local Supabase (via supabase CLI) and have a Node/Express backend query a table (projects) using @supabase/supabase-js.
- Verify health with a small script that does a simple select: id, updated_at from projects limit 1.
What’s going wrong
- The SDK initializes, but the REST query fails with:
- JWSError (CompactDecodeError Invalid number of parts: Expected 3 parts; got 1)
- Code: PGRST301
- This points to PostgREST rejecting the Authorization token (not a valid JWT).
- I’m using the new-style local keys supabase status prints: sbpublishable... and sbsecret...
- If these keys end up in Authorization: Bearer ..., the error occurs.
Environment
- OS: macOS
- Framework: Node/Express (backend)
- Library version:
- @supabase/supabase-js: ^2.57.1
- Running locally with supabase CLI (self-hosted dev)
supabase --version 2.45.5
It was working before(yesterday)
But stopped working after I nuked my local environment and started from scratch.
CODE:
Tried different variations but for whatever reason it errors out.
Hot to get JWT tokens from Supabase CLI?
SOLVED: by downgraded cli version to 2.39.231 Replies
The new keys don't work locally yet.

Thank you, but my local CLI supabase started to return only new api keys,
how to roll back to JWT back?
@garyaustin to clarify:
- installed latest supabase cli
- i've run supabase start
and it setups project with new keys locally.
Update: downgrading to lower version is working.
npx supabase@2.39.2 start works.
But latest supabase CLI has a bug.How do you setup project with the new keys locally?
Just reinstalled supabase with home brew and run supabase start
Maybe something specific I can help with?
When I downgraded to using npx supabase@older version it started to work fine
This by itself wouldn't have the new keys locally. Did you like to a remote Supabase project?
Looks like it was supposed to be added to CLI for local dev recently...
https://github.com/orgs/supabase/discussions/29260#discussioncomment-14422928
I have linked and I think I’ve generated in web. I can try to unlink locally
Or that PR have broken things 😬
Ah it was added to
2.45.0 and is part of the latest public release 2.45.5.
I will test this out on my project and see if I'm getting the same results as you are.Thank you!
I just tested this and it works without any issue for me.
I'm also getting the same error as OP locally with CLI v2.45.5 and supabase-js 2.57.4. It also happens in CI where we run some tests against a Supabase instance running inside the CI container.
In my case, I'm using the secret key but get the same result with the publishable key. This does not happen with
createServerClient from @supabase/ssr, presumably because it is using the logged in user's JWT for the auth headers.
Here's a minimal reproduction of the issue: https://github.com/jmay4826/supabase-cli-reproI'm going to test it out
Yeah I can reproduce with your example. I didn't get that issue in my example however. I will keep on investigating this, it means there is still a check in postgrest that is stopping this from working correctly.
Thank you!
@silentworks Why do you think PostgREST is involved? I'm pretty sure it is up to Kong (or some patch for local) to convert the new keys to the old anon/service role keys before calling the REST API's. This is why edge functions don't work. That is my understanding at least.
https://github.com/supabase/cli/pull/4167/files#diff-1af1ea8d4dac7cf62987c89e0f1036ad192403d7135f445d719993f0f5303a96
That is also paired with this change requiring later clients to keep the authorization header only JWT. (I assume silentworks knows this part as he works on one of the clients).
If anything gets the Authorization header set to the new API key it will fail.

Note if you are running your own curl type commands you would need to populate ONLY the apikey with the new keys and NOT the authorization header. The authorization header HAS to be a JWT (old anon/service_role/user jwt) or nothing.
The reason I thought this is because in my Python project there is no issue. When I said PostgREST I meant postgrest-js and not the actual service, although the error code looks like a service level error code.
Ah. I don't see that postgrest-js does anything with apikey or authentication header at all. But Supabase-js as above does. Assume it handles for both. The error is likely from PostgREST server because for some reason the authentication header is the new style apikey, which it knows nothing about.
Well that would be weird that my Python code doesn’t run into this issue whilst this JS repo does. Now I’m wondering if my code is running from a cached version or something. I’ll look into it a bit more
OK a bit odd. I forced the Authorization header to 'bearer publishableKey' in createClient. The JS code implies that is an error.... But it sent it and the auth server bitched about it.
Although this seems really screwed up as it sends two copies of Bearer publishablekey...
Sigh...


That looks broken
So the double thing occurs even with the regular key.
Not something I've used in awhile though. But I don't see why my code would generate two and I thought it was valid to set header that way as used to be done in Edge functions.
Could it be case sensitive? Maybe try
Authorization instead.Works correct for old key if I go to 2.49.8
Double repeat for latest with lower case authorization, but not 2.49.8. But still fails as it passes the SB...... apikey thru if set in authorization header.
SOOOO
Latest copies SB into the authorization header just like it always it appears. BUT on hosted it works...

That is just a plain createClient rest DB call.
Hosted must use a different algo, smarter maybe and cleans up the authorization header even if populated with non-jwt.
The local code I think expects it to be empty, which the supabase-js PR I showed seems to do...
GitHub
feat: do not send non-JWTs in
Authorization header by hf · Pull ...In preparation for the introduction of new API keys, the client library should not pass non-JWT values in the Authorization header, as requests like this will definitely fail.
Two backward compatib...


So CLI has to handle this differently.
Or Auth has to change to not provide non JWT's in the authorization header.
Looks like some fixes to the CLI being done.


You can test this out using
npx supabase@beta start
I've tested the latest beta version of the CLI with your reproduction repo and it works as expected now.