auth icon indicating copy to clipboard operation
auth copied to clipboard

feat(oauth): add Supabase OAuth provider

Open cemalkilic opened this issue 2 months ago • 1 comments

Summary

This PR adds support for using Supabase Auth as an OAuth 2.1 provider with full PKCE support, enabling Supabase Auth instances to federate authentication to other Supabase Auth instances. This implements the OAuth 2.1 capabilities discussed in https://github.com/orgs/supabase/discussions/38022.

What Changed

1. New Supabase OAuth Provider (internal/api/provider/supabase.go)

  • Implements OAuth 2.1 authorization code flow with PKCE. (PKCE is a must for OAuth2.1 Authorization Code flow)
  • Temporary Implementation: Currently decodes user data from JWT claims instead of calling a /userinfo endpoint
    • TODO: Update to use OpenID Connect Discovery when Supabase Auth supports OIDC
    • TODO: Update to call /userinfo endpoint when available
  • Scopes: Currently placeholder implementation (not yet supported by Supabase Auth OAuth 2.1)
  • Extracts and preserves app_metadata and user_metadata as custom claims

2. Generic PKCE Support for OAuth Providers

Added code to support dual PKCE flows:

  • User PKCE: Code challenge/verifier between end user and this auth instance
  • Provider PKCE: Separate code challenge/verifier between this instance and external provider

Currently, only supabase auth requires PKCE but added the code to make it future proof as OAuth2.1 adoption is increasing. Added RequiresPKCE() method (returns false by default) to all 25 existing providers

Flow Matrix:

User Flow Provider Requires PKCE FlowState Created? Result
PKCE Yes Auth code (both PKCEs)
PKCE No Auth code (user PKCE only)
Implicit Yes Token (provider PKCE internal)
Implicit No Token (traditional implicit)

Configuration

Users can configure the Supabase provider via environment variables:

GOTRUE_EXTERNAL_SUPABASE_ENABLED=true
GOTRUE_EXTERNAL_SUPABASE_CLIENT_ID=your-oauth-client-id
GOTRUE_EXTERNAL_SUPABASE_SECRET=your-oauth-client-secret
GOTRUE_EXTERNAL_SUPABASE_URL=https://other-supabase-project.supabase.co/auth/v1
GOTRUE_EXTERNAL_SUPABASE_REDIRECT_URI=https://your-auth-instance.supabase.co/auth/v1/callback

Technical Highlights

  1. No Supabase-specific conditionals in flow logic. All PKCE handling works for any provider via the RequiresPKCE() interface method.
  2. Uses golang.org/x/oauth2 Built-in PKCE:
    • oauth2.GenerateVerifier() - generates code verifier
    • oauth2.S256ChallengeOption() - adds challenge to auth URL
    • oauth2.VerifierOption() - adds verifier to token exchange
  3. Separation of Concerns:
    • User's PKCE stored in FlowState.CodeChallenge and verified against user's verifier
    • Provider's PKCE stored in FlowState.ProviderCodeVerifier and sent to provider during token exchange
    • Both flows are completely independent

Manual Testing Scenarios:

  1. ✅ User PKCE + Supabase provider (dual PKCE)
  2. ✅ User implicit + Supabase provider (provider PKCE only, return token)
  3. ✅ User PKCE + non-PKCE provider (user PKCE only)
  4. ✅ User implicit + non-PKCE provider (traditional implicit)

cemalkilic avatar Oct 29 '25 09:10 cemalkilic