0008. Authentication & Token Management
Status: proposed Date: 2026-02-10
Problem Statement
Auth is referenced in ADRs 0001 (error codes 3/AUTH_*), 0002 (identity lifecycle), 0004 (command surface), and 0006 (user_id for env management) — but no ADR captures the actual design decisions for how login, token storage, and multi-profile work.
The new supabase CLI should be compatible with the existing Go CLI's credential store so users don't need to re-login when switching between CLIs.
Key Decisions to Cover
- Login flow: Keep the browser-based ECDH login flow? Or switch to standard OAuth device flow?
- Token storage: Keep keyring-first storage with file fallback? Token loading priority (env var → keyring → legacy keyring → token file)?
- Token format: Keep the
sbp_token format validation (^sbp_(oauth_)?[a-f0-9]{40}$)? - Legacy token migration: How should the CLI handle any legacy on-disk token formats while reading old tokens?
- Profile system: Keep built-in profiles (supabase, supabase-staging, supabase-local, snap) or simplify to user-defined profiles?
- Backward compatibility: Should
supabase logindetect an existing Go CLI token and reuse it? - Token refresh: Keep the no-refresh model (long-lived, server-managed expiry) or add refresh tokens?
Context: How Auth Works in the Go CLI
Login flow — Browser-based with end-to-end encryption:
- CLI generates a session UUID and an ECDH P256 keypair
- Opens browser to
https://supabase.com/dashboard/cli/login?session_id=...&public_key=...&token_name=cli_<user>@<host>_<timestamp> - User authenticates in browser; dashboard encrypts the access token with the CLI's public key via ECDH + AES-GCM
- CLI polls
GET /platform/cli/login/<session_id>until it gets the encrypted token - CLI decrypts using ECDH shared secret + AES-GCM, validates format, stores token
- Alternative:
supabase login --token <token>for non-interactive (CI)
Token storage — Multi-tier with fallback:
- System keyring (primary) — via
zalando/go-keyring: macOS Keychain, Linux Secret Service, Windows Credential Manager. Namespace:"Supabase CLI", key: profile name - Token file (fallback) —
~/.supabase/access-token, plain text,0600permissions. Used when keyring is unavailable
Token loading priority:
SUPABASE_ACCESS_TOKENenv var (highest)- Keyring for current profile
- Legacy keyring key (
"access-token"— backward compat) - Token file
~/.supabase/access-token
No token refresh — Tokens are long-lived, server-managed expiry. User must re-login when expired.