Skip to main content

Source: ocean/docs/adr/0007-migrate-to-publishable-keys.md | ✏️ Edit on GitHub

ADR-0007: Migrate from Legacy JWT Keys to Publishable/Secret API Keys

Status

Accepted

Context

Currently using legacy JWT-based API keys (anon_key and service_role) which:

  • Are tied to the legacy JWT secret that we want to rotate
  • Don't have the same security protections as new publishable/secret keys
  • Prevent us from fully migrating away from the legacy JWT secret

Supabase now offers a modern API key system:

  • Publishable keys: For client-side use (replaces anon_key)
  • Secret keys: For server-side use (replaces service_role)

Decision

Migrate from legacy JWT-based keys to the new publishable/secret key system to:

  1. Enable rotation of the legacy JWT secret
  2. Improve security with built-in protections
  3. Align with Supabase's recommended practices

Implementation

1. Client-Side Changes (Browser)

Replace VITE_SUPABASE_ANON_KEY with VITE_SUPABASE_PUBLISHABLE_KEY:

// Old
const supabase = createClient(url, anonKey)

// New
const supabase = createClient(url, publishableKey)

2. Environment Variables

Update all environment files:

# Remove
VITE_SUPABASE_ANON_KEY=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...

# Add
VITE_SUPABASE_PUBLISHABLE_KEY=pk_live_...

3. Server-Side (if applicable)

For any server-side operations, use secret keys instead of service_role:

# Remove
SUPABASE_SERVICE_ROLE_KEY=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...

# Add
SUPABASE_SECRET_KEY=sk_live_...

Migration Steps

  1. Generate new keys in Supabase Dashboard > Settings > API
  2. Update environment variables in all environments
  3. Deploy changes to all clients
  4. Monitor for any authentication issues
  5. Deactivate legacy keys after confirming all clients migrated
  6. Rotate legacy JWT secret once legacy keys are no longer in use

Consequences

Positive

  • Can rotate legacy JWT secret without breaking existing clients
  • Better security with built-in browser detection for secret keys
  • Clearer distinction between public and private keys
  • Aligned with Supabase best practices

Negative

  • Requires updating all environment configurations
  • Need to coordinate deployment across all environments
  • Brief period where both key systems are active

Limitations to Consider

  • New keys can't be used in Authorization Bearer header
  • Edge Functions require --no-verify-jwt flag with new keys
  • Realtime connections have 24-hour limitation with new keys

References