Skip to content

Supabase CLI 2.109.1 on Windows can resolve different Management API identities from different process contexts on the same computer and Windows user account. #5890

Description

@pifoub

Affected area

Auth

Supabase CLI version

v2.109.1

Operating system

Windows 11

Installation method

Other

Command

Installation method: Scoop. not tied to command

Actual output

## Description

Supabase CLI 2.109.1 on Windows can resolve different Management API identities from different process contexts on the same computer and Windows user account.

The persistent Windows generic credential is:

- Target: `Supabase CLI:supabase`
- Username/account: `supabase`
- Type: `CRED_TYPE_GENERIC`
- Persistence: `CRED_PERSIST_LOCAL_MACHINE`

Repeated `supabase logout` commands exited successfully, but the credential remained. Its Windows `LastWritten` timestamp did not change, proving it was not deleted and recreated.

## Environment

- Windows 11
- Supabase CLI 2.109.1
- Installed through Scoop
- PowerShell 7.6.3
- Hosted Supabase projects under two different Supabase identities
- Commands run both interactively and through a desktop application's non-interactive process runner

## Observed behavior

Sanitized CLI traces identify two distinct authenticated Supabase users through the Management API response identity.

A representative sequence:

1. Interactive `supabase login` authenticates Identity B.
2. Interactive `supabase link` succeeds against Identity B's project.
3. Interactive `supabase projects list` returns Identity B's projects.
4. Minutes later, a non-interactive `supabase projects list` launched through another process context returns Identity A's projects.
5. No login, startup task, environment-variable change, or credential write occurs between steps 3 and 4.

This occurred repeatedly.

The behavior presents as if a deleted or replaced credential is being restored, but trace evidence instead shows different Windows process/security contexts resolving different authenticated identities.

## Logout behavior

Multiple `supabase logout` commands returned exit status 0, while the original Windows credential remained readable.

The CLI implementation treats keyring-unavailable/not-found as a successful not-logged-in outcome, so exit status 0 does not establish that the credential was deleted.

## Profile-file behavior

Deleting:

    C:\Users\<user>\.supabase\profile

does not prevent credential loading. Debug output shows:

    NotFound: FileSystem.readFile (...\.supabase\profile)
    Using access token for profile: supabase
    Using profile: supabase (supabase.co)

The CLI silently falls back to the built-in `supabase` profile and continues reading the Windows credential.

## Expected behavior

- The same Windows user and `CRED_PERSIST_LOCAL_MACHINE` target should resolve consistently across supported execution contexts.
- `supabase logout` should delete every current and legacy credential representation.
- Logout should not report success when the targeted credential remains.
- The CLI should expose which credential backend and exact target it is using.
- If the process cannot access or delete the expected credential context, it should return a clear nonzero error.
- A command must not silently target a different Supabase account or project because of process-launch context.

## Impact

This is more than a login inconvenience. A developer can believe they are operating against one Supabase account while migration, link, or database commands authenticate as another account.

That creates a risk of applying database changes to the wrong hosted project.

## Relevant implementation

Windows keyring lookup, legacy-target handling, and deletion:

https://github.com/supabase/cli/blob/v2.109.1/apps/cli/src/legacy/auth/legacy-credentials.layer.ts

Access-token lookup order:

https://github.com/supabase/cli/blob/v2.109.1/apps/cli-go/internal/utils/access_token.go

Logout behavior:

https://github.com/supabase/cli/blob/v2.109.1/apps/cli/src/legacy/commands/logout/logout.handler.ts

I can provide a sanitized timeline of command traces and Windows credential metadata. Raw trace files cannot be attached because CLI 2.109.1 also records unredacted project secret keys in those files; that security issue is being reported separately.

Expected behavior

The same Windows user and CRED_PERSIST_LOCAL_MACHINE target should resolve consistently across supported execution contexts.

Steps to reproduce

  1. On Windows 11 with Supabase CLI 2.109.1, create an isolated Supabase home with no telemetry configuration:

    $env:SUPABASE_HOME = Join-Path $env:TEMP ("supabase-cli-trace-repro-" + [guid]::NewGuid())
    Do not run supabase telemetry enable.

Create a minimal CLI project:
New-Item -ItemType Directory supabase-trace-repro
Set-Location supabase-trace-repro
supabase init

Authenticate normally:
supabase login

Link a throwaway hosted project that uses the current sb_publishable_ / sb_secret_ API-key format:
supabase link --project-ref
No secret key needs to be supplied manually. The CLI obtains the project keys while linking and uses the secret key for its REST, Auth, and Storage health requests.

Locate the newest automatically created trace:
$tracePath = (
Get-ChildItem "$env:SUPABASE_HOME\traces*.ndjson" |
Sort-Object LastWriteTime |
Select-Object -Last 1
).FullName

Run this redacting check. It reports whether an unredacted secret exists without printing the key:
Get-Content $tracePath | ForEach-Object {
try {
$event = $_ | ConvertFrom-Json -ErrorAction Stop
} catch {
return
}

$apiKey = [string]$event.attributes.'http.request.header.apikey'

if ($apiKey) {
[pscustomobject]@{
Path = [string]$event.attributes.'url.path'
IsUnredactedSecretKey = $apiKey.StartsWith('sb_secret_')
IsRedacted = $apiKey -eq ''
}
}
}

Observe entries for endpoints such as /rest/v1/, /auth/v1/health, and /storage/v1/version where:
IsUnredactedSecretKey : True
IsRedacted : False

Expected result: credentials are never written to trace files, or the apikey value is recorded only as .
Actual result: the complete sb_secret_ value is stored in the NDJSON trace despite telemetry never being explicitly enabled.

Crash report ID

No response

Docker and service versions

n/a

Additional context

No response

Metadata

Metadata

Assignees

Type

No type

Fields

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