diff --git a/README.md b/README.md index 8e4955f..8c5874e 100644 --- a/README.md +++ b/README.md @@ -236,8 +236,13 @@ Status conditions: | `siteURL` | Application URL | Required | | `externalURL` | Auth service URL | Required | | `autoConfirmEmail` | Skip email confirmation | false | +| `enableAnonymousUsers` | Allow sign-in without email or another identity | false | | `providers.secretRef` | Secret with OAuth credentials | - | +Anonymous users still use the `authenticated` PostgreSQL role and receive an +`is_anonymous` JWT claim. Add abuse controls before enabling anonymous sign-ins +on a publicly advertised service. + ### REST (PostgREST) | Field | Description | Default | diff --git a/api/v1alpha1/supabaseproject_types.go b/api/v1alpha1/supabaseproject_types.go index f0d3d54..8862c92 100644 --- a/api/v1alpha1/supabaseproject_types.go +++ b/api/v1alpha1/supabaseproject_types.go @@ -347,6 +347,12 @@ type AuthSpec struct { // +optional DisableSignup bool `json:"disableSignup,omitempty"` + // EnableAnonymousUsers permits sign-in without email or another identity. + // Anonymous users use the authenticated Postgres role and receive an is_anonymous JWT claim. + // +kubebuilder:default=false + // +optional + EnableAnonymousUsers bool `json:"enableAnonymousUsers,omitempty"` + // AutoConfirmEmail enables automatic email confirmation // +kubebuilder:default=true // +optional diff --git a/charts/cloudnative-supabase/crds/supabase.guion.dev_supabaseprojects.yaml b/charts/cloudnative-supabase/crds/supabase.guion.dev_supabaseprojects.yaml index 97f1c11..f31b416 100644 --- a/charts/cloudnative-supabase/crds/supabase.guion.dev_supabaseprojects.yaml +++ b/charts/cloudnative-supabase/crds/supabase.guion.dev_supabaseprojects.yaml @@ -75,6 +75,12 @@ spec: - enabled - uri type: object + enableAnonymousUsers: + default: false + description: |- + EnableAnonymousUsers permits sign-in without email or another identity. + Anonymous users use the authenticated Postgres role and receive an is_anonymous JWT claim. + type: boolean externalURL: description: ExternalURL is the public URL of the auth service type: string diff --git a/config/crd/bases/supabase.guion.dev_supabaseprojects.yaml b/config/crd/bases/supabase.guion.dev_supabaseprojects.yaml index 97f1c11..f31b416 100644 --- a/config/crd/bases/supabase.guion.dev_supabaseprojects.yaml +++ b/config/crd/bases/supabase.guion.dev_supabaseprojects.yaml @@ -75,6 +75,12 @@ spec: - enabled - uri type: object + enableAnonymousUsers: + default: false + description: |- + EnableAnonymousUsers permits sign-in without email or another identity. + Anonymous users use the authenticated Postgres role and receive an is_anonymous JWT claim. + type: boolean externalURL: description: ExternalURL is the public URL of the auth service type: string diff --git a/config/samples/supabase_v1alpha1_supabaseproject.yaml b/config/samples/supabase_v1alpha1_supabaseproject.yaml index 05690b7..40c705a 100644 --- a/config/samples/supabase_v1alpha1_supabaseproject.yaml +++ b/config/samples/supabase_v1alpha1_supabaseproject.yaml @@ -18,6 +18,7 @@ spec: siteURL: https://app.example.com externalURL: https://auth.example.com autoConfirmEmail: true + enableAnonymousUsers: false providers: google: enabled: true diff --git a/internal/resources/deployments/auth.go b/internal/resources/deployments/auth.go index 3a66f0d..59102e9 100644 --- a/internal/resources/deployments/auth.go +++ b/internal/resources/deployments/auth.go @@ -145,6 +145,7 @@ func buildAuthEnv(project *supabasev1alpha1.SupabaseProject, secretNames *supaba // Signup configuration corev1.EnvVar{Name: "GOTRUE_DISABLE_SIGNUP", Value: fmt.Sprintf("%t", spec.DisableSignup)}, + corev1.EnvVar{Name: "GOTRUE_EXTERNAL_ANONYMOUS_USERS_ENABLED", Value: fmt.Sprintf("%t", spec.EnableAnonymousUsers)}, // Email configuration corev1.EnvVar{Name: "GOTRUE_EXTERNAL_EMAIL_ENABLED", Value: "true"}, diff --git a/internal/resources/deployments/auth_test.go b/internal/resources/deployments/auth_test.go index 9a4c5ac..cb1a8bd 100644 --- a/internal/resources/deployments/auth_test.go +++ b/internal/resources/deployments/auth_test.go @@ -6,6 +6,46 @@ import ( supabasev1alpha1 "github.com/GuionAI/cloudnative-supabase/api/v1alpha1" ) +func TestAuthDeploymentRendersAnonymousSignInsSetting(t *testing.T) { + tests := []struct { + name string + enableAnonymousUsers bool + want string + }{ + { + name: "omitted defaults to disabled", + want: "false", + }, + { + name: "enabled", + enableAnonymousUsers: true, + want: "true", + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + project := newTestProject(testNamespace) + project.Spec.Auth.EnableAnonymousUsers = tt.enableAnonymousUsers + + deployment := BuildAuthDeployment(project, newTestSecretNames()) + count := 0 + for _, variable := range deployment.Spec.Template.Spec.Containers[0].Env { + if variable.Name != "GOTRUE_EXTERNAL_ANONYMOUS_USERS_ENABLED" { + continue + } + count++ + if variable.Value != tt.want { + t.Errorf("GOTRUE_EXTERNAL_ANONYMOUS_USERS_ENABLED = %q, want %q", variable.Value, tt.want) + } + } + if count != 1 { + t.Errorf("GOTRUE_EXTERNAL_ANONYMOUS_USERS_ENABLED count = %d, want 1", count) + } + }) + } +} + func TestAuthEmailHookUsesGeneratedSigningSecret(t *testing.T) { project := newTestProject(testNamespace) project.Spec.Auth.EmailHook = &supabasev1alpha1.EmailHookSpec{