You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
supabase link / projects api-keys: 403 insufficient privileges, but identical token succeeds via direct API call #6392
supabase link / supabase projects api-keys fail with "insufficient privileges" while the identical token succeeds via direct API call
Bug report
supabase link (and supabase projects api-keys) fail with an "insufficient privileges" error, while the exact same personal access token, hitting the equivalent Management API endpoint, succeeds via a plain curl call.
Environment
CLI version: 2.116.0 (also reproduced on 2.107.0 before upgrading)
OS: macOS (Darwin 25.6.0)
Install method: Homebrew
Org plan: Pro, Owner role, billing/payment method on file
Steps to reproduce
supabase link --project-ref <ref>
Output:
{"_tag":"Error","error":{"code":"LegacyLinkProjectStatusError","message":"Unexpected error retrieving remote project status: {\"message\":\"Your account does not have the necessary privileges to access this endpoint. For more details, refer to our documentation https://supabase.com/docs/guides/platform/access-control\"}"}}
supabase projects api-keys --project-ref <ref> fails the same way.
Proof the token itself is fine
Using the sameSUPABASE_ACCESS_TOKEN the CLI is resolving (verified via env var, not --profile, see below), a direct call to the Management API succeeds:
Same token, same project, same account — CLI rejects it, raw REST call accepts it.
What we ruled out
Token scope — token has full scope, confirmed via the dashboard.
Org role — Owner.
Billing — payment method on file, no past-due invoices.
Plan tier — Pro.
CLI version — reproduced on both 2.107.0 and the latest 2.116.0 at time of filing.
Local CLI state/cache — deleted ~/.supabase/profile and other local CLI state, re-authenticated from scratch, still reproduces.
--profile isolation — also found that --profile doesn't appear to isolate credentials as expected (logging a token under an unrelated profile name still authenticated as the real account), so we're resolving the token via SUPABASE_ACCESS_TOKEN env var instead, not --profile. Not certain this is related to the 403, flagging in case it's the same root cause (e.g. profile/account resolution picking the wrong context internally before the privilege check).
Impact
Can't use supabase link / supabase db push / supabase projects api-keys at all against this project. Working around it by scripting equivalent calls directly against the Management API (POST /v1/projects/{ref}/database/query), which work fine and confirms the backend/account itself has no permission issue — this looks CLI-internal.
I am also hitting this one, and it's a weird one because nothing changed on my end. Same token that worked earlier today suddenly started getting 403s from the CLI, while the API itself is perfectly happy with it.
CLI 2.111.0 and 2.117.0; Windows 11 and GitHub Actions (ubuntu)
Scoped token, read-write on 33 capabilities, scoped to the one project
Worked earlier the same day on the identical CLI/token; broke with no repo/token changes
Happy to share the project ref privately with a maintainer if that helps
supabase link --project-ref --debug
HTTP GET: https://api.supabase.com/v1/projects/<project-ref>
HTTP GET: https://api.supabase.com/v1/projects/<project-ref>/api-keys
Authorization failed for the access token and project ref pair: {"message":"Your account does not have the necessary privileges to access this endpoint. For more details, refer to our documentation https://supabase.com/docs/guides/platform/access-control"}
So the token and /api-keys both work directly, but the CLI's request gets denied.
Workaround that still works for me (link/api-keys seems to be the only broken path):
supabase db push --project-ref <project-ref> --password <db-password> # works
supabase functions deploy <fn> --project-ref <project-ref> # works
supabase secrets set --project-ref <project-ref> ... # works
Impact: supabase link (and any --linked flow) is unusable, so automated CI migrations/deploys are blocked. Thanks!
Another data point, narrowed to a single endpoint: the 403 is on ?reveal=true, not on /api-keys itself.
Probing three Management API endpoints with the same PAT, from a GitHub Actions runner, status codes only (curl -s -o /dev/null -w '%{http_code}'):
endpoint
status
GET /v1/projects/{ref}
200
GET /v1/projects/{ref}/api-keys
200
GET /v1/projects/{ref}/api-keys?reveal=true
403
supabase link --project-ref {ref} then fails in the same run with Authorization failed for the access token and project ref pair: {"message":"Your account does not have the necessary privileges to access this endpoint. ..."}.
So listing the key entries is permitted to this token while revealing their values is not, and link reveals them in order to cache them locally. That seems to be the whole of it. supabase projects list also succeeds on the same token and returns the project, so it is not project visibility.
Same result on both CLI versions, same project, same token, minutes apart:
2.116.0: 200 / 200 / 403, link fails.
2.117.0 (verified via supabase --version in the run, since supabase/setup-cli does not log what it resolved): 200 / 200 / 403, link fails identically.
That rules out a regression between those two releases, which matches this issue already reproducing on 2.107.0.
Two things that might be worth considering upstream, if the ?reveal=true gate is intentional:
link could degrade rather than fail when the key reveal is refused. Resolving the project succeeds, and the cached key values are not needed by every subsequent command.
The error text could name the endpoint that was refused. "Authorization failed for the access token and project ref pair" points at the token/ref pair, which is what sent us looking in the wrong place for a while, since both of those are in fact fine.
Workaround for CI, in case it helps anyone else here: skip link entirely and pass --db-url (session pooler host, port 5432) to supabase db push and supabase migration list. That keeps the Management API off the path completely.
Same here: project-scoped PAT created by the org Owner, CLI 2.120.0, GitHub Actions (ubuntu-latest). link fails on GET /v1/projects//api-keys and only passes after adding the "API Key Secrets: read" capability.
That means a CI token has to be able to read the service_role key just to run db push, which itself only needs the database password. Opened #7165 for that least-privilege side.
+1 for link degrading gracefully when key reveal is refused. Working around it with db push --db-url (session pooler, port 5432) and no access token.
Activity
ci(db): set SUPABASE_PROJECT_REF explicitly in token-dependent workflows
ci(db): use Management API instead of supabase link for token workflows
DotNetTitan commentedon Sep 10, 2026
I am also hitting this one, and it's a weird one because nothing changed on my end. Same token that worked earlier today suddenly started getting 403s from the CLI, while the API itself is perfectly happy with it.
supabase link --project-ref --debug
Same token, direct REST, both 200:
So the token and /api-keys both work directly, but the CLI's request gets denied.
Workaround that still works for me (link/api-keys seems to be the only broken path):
Impact: supabase link (and any --linked flow) is unusable, so automated CI migrations/deploys are blocked. Thanks!
fix(ci): use db push/query --project-ref instead of supabase link
fix(ci): migrate staging and production without supabase link (#158)
SBub commentedon Sep 21, 2026
Another data point, narrowed to a single endpoint: the 403 is on
?reveal=true, not on/api-keysitself.Probing three Management API endpoints with the same PAT, from a GitHub Actions runner, status codes only (
curl -s -o /dev/null -w '%{http_code}'):GET /v1/projects/{ref}GET /v1/projects/{ref}/api-keysGET /v1/projects/{ref}/api-keys?reveal=truesupabase link --project-ref {ref}then fails in the same run withAuthorization failed for the access token and project ref pair: {"message":"Your account does not have the necessary privileges to access this endpoint. ..."}.So listing the key entries is permitted to this token while revealing their values is not, and
linkreveals them in order to cache them locally. That seems to be the whole of it.supabase projects listalso succeeds on the same token and returns the project, so it is not project visibility.Same result on both CLI versions, same project, same token, minutes apart:
supabase --versionin the run, sincesupabase/setup-clidoes not log what it resolved): 200 / 200 / 403, link fails identically.That rules out a regression between those two releases, which matches this issue already reproducing on 2.107.0.
Two things that might be worth considering upstream, if the
?reveal=truegate is intentional:linkcould degrade rather than fail when the key reveal is refused. Resolving the project succeeds, and the cached key values are not needed by every subsequent command.Workaround for CI, in case it helps anyone else here: skip
linkentirely and pass--db-url(session pooler host, port 5432) tosupabase db pushandsupabase migration list. That keeps the Management API off the path completely.Spiatron commentedon Oct 14, 2026
Same here: project-scoped PAT created by the org Owner, CLI 2.120.0, GitHub Actions (ubuntu-latest).
linkfails on GET /v1/projects//api-keys and only passes after adding the "API Key Secrets: read" capability.That means a CI token has to be able to read the service_role key just to run
db push, which itself only needs the database password. Opened #7165 for that least-privilege side.+1 for
linkdegrading gracefully when key reveal is refused. Working around it withdb push --db-url(session pooler, port 5432) and no access token.