Documentation ¶
Index ¶
- func FindPublicKeyByKid(kid string, config *JWTConfiguration) (any, error)
- func GetSigningAlg(k jwk.Key) jwt.SigningMethod
- func GetSigningJwk(config *JWTConfiguration) (jwk.Key, error)
- func GetSigningKey(k jwk.Key) (any, error)
- func LoadDirectory(configDir string) error
- func LoadFile(filename string) error
- type APIConfiguration
- type AnonymousProviderConfiguration
- type CORSConfiguration
- type CaptchaConfiguration
- type DBConfiguration
- type DatabaseEncryptionConfiguration
- type EmailContentConfiguration
- type EmailProviderConfiguration
- type ExtensibilityPointConfiguration
- type GlobalConfiguration
- type HIBPBloomConfiguration
- type HIBPConfiguration
- type HTTPHookSecrets
- type HookConfiguration
- type JWTConfiguration
- type JwkInfo
- type JwtKeysDecoder
- type LoggingConfig
- type MFAConfiguration
- type MFAFactorTypeConfiguration
- type MailerConfiguration
- type MessagebirdProviderConfiguration
- type MetricsConfig
- type MetricsExporter
- type OAuthProviderConfiguration
- type PasswordConfiguration
- type PasswordRequiredCharacters
- type PhoneFactorTypeConfiguration
- type PhoneProviderConfiguration
- type ProfilerConfig
- type ProviderConfiguration
- type SAMLConfiguration
- type SMTPConfiguration
- type SecurityConfiguration
- type SessionsConfiguration
- type SmsProviderConfiguration
- type TOTPFactorTypeConfiguration
- type TextlocalProviderConfiguration
- type Time
- type TracingConfig
- type TracingExporter
- type TwilioProviderConfiguration
- type TwilioVerifyProviderConfiguration
- type VonageProviderConfiguration
Constants ¶
This section is empty.
Variables ¶
This section is empty.
Functions ¶
func FindPublicKeyByKid ¶
func FindPublicKeyByKid(kid string, config *JWTConfiguration) (any, error)
func GetSigningAlg ¶
func GetSigningJwk ¶
func GetSigningJwk(config *JWTConfiguration) (jwk.Key, error)
func LoadDirectory ¶
LoadDirectory does nothing when configDir is empty, otherwise it will attempt to load a list of configuration files located in configDir by using ReadDir to obtain a sorted list of files containing a .env suffix.
When the list is empty it will do nothing, otherwise it passes the file list to godotenv.Overload to pull them into the current environment.
Types ¶
type APIConfiguration ¶
type APIConfiguration struct { Host string Port string `envconfig:"PORT" default:"8081"` Endpoint string RequestIDHeader string `envconfig:"REQUEST_ID_HEADER"` ExternalURL string `json:"external_url" envconfig:"API_EXTERNAL_URL" required:"true"` MaxRequestDuration time.Duration `json:"max_request_duration" split_words:"true" default:"10s"` }
func (*APIConfiguration) Validate ¶
func (a *APIConfiguration) Validate() error
type AnonymousProviderConfiguration ¶
type AnonymousProviderConfiguration struct {
Enabled bool `json:"enabled" default:"false"`
}
type CORSConfiguration ¶
type CORSConfiguration struct {
AllowedHeaders []string `json:"allowed_headers" split_words:"true"`
}
func (*CORSConfiguration) AllAllowedHeaders ¶
func (c *CORSConfiguration) AllAllowedHeaders(defaults []string) []string
type CaptchaConfiguration ¶
type CaptchaConfiguration struct { Enabled bool `json:"enabled" default:"false"` Provider string `json:"provider" default:"hcaptcha"` Secret string `json:"provider_secret"` }
func (*CaptchaConfiguration) Validate ¶
func (c *CaptchaConfiguration) Validate() error
type DBConfiguration ¶
type DBConfiguration struct { Driver string `json:"driver" required:"true"` URL string `json:"url" envconfig:"DATABASE_URL" required:"true"` Namespace string `json:"namespace" envconfig:"DB_NAMESPACE" default:"auth"` // MaxPoolSize defaults to 0 (unlimited). MaxPoolSize int `json:"max_pool_size" split_words:"true"` MaxIdlePoolSize int `json:"max_idle_pool_size" split_words:"true"` ConnMaxLifetime time.Duration `json:"conn_max_lifetime,omitempty" split_words:"true"` ConnMaxIdleTime time.Duration `json:"conn_max_idle_time,omitempty" split_words:"true"` HealthCheckPeriod time.Duration `json:"health_check_period" split_words:"true"` MigrationsPath string `json:"migrations_path" split_words:"true" default:"./migrations"` CleanupEnabled bool `json:"cleanup_enabled" split_words:"true" default:"false"` }
DBConfiguration holds all the database related configuration.
func (*DBConfiguration) Validate ¶
func (c *DBConfiguration) Validate() error
type DatabaseEncryptionConfiguration ¶
type DatabaseEncryptionConfiguration struct { Encrypt bool `json:"encrypt"` EncryptionKeyID string `json:"encryption_key_id" split_words:"true"` EncryptionKey string `json:"-" split_words:"true"` DecryptionKeys map[string]string `json:"-" split_words:"true"` }
DatabaseEncryptionConfiguration configures Auth to encrypt certain columns. Once Encrypt is set to true, data will start getting encrypted with the provided encryption key. Setting it to false just stops encryption from going on further, but DecryptionKeys would have to contain the same key so the encrypted data remains accessible.
func (*DatabaseEncryptionConfiguration) Validate ¶
func (c *DatabaseEncryptionConfiguration) Validate() error
type EmailContentConfiguration ¶
type EmailContentConfiguration struct { Invite string `json:"invite"` Confirmation string `json:"confirmation"` Recovery string `json:"recovery"` EmailChange string `json:"email_change" split_words:"true"` MagicLink string `json:"magic_link" split_words:"true"` Reauthentication string `json:"reauthentication"` }
EmailContentConfiguration holds the configuration for emails, both subjects and template URLs.
type ExtensibilityPointConfiguration ¶
type ExtensibilityPointConfiguration struct { URI string `json:"uri"` Enabled bool `json:"enabled"` // For internal use together with Postgres Hook. Not publicly exposed. HookName string `json:"-"` // We use | as a separator for keys and : as a separator for keys within a keypair. For instance: v1,whsec_test|v1a,whpk_myother:v1a,whsk_testkey|v1,whsec_secret3 HTTPHookSecrets HTTPHookSecrets `json:"secrets" envconfig:"secrets"` }
func (*ExtensibilityPointConfiguration) PopulateExtensibilityPoint ¶
func (e *ExtensibilityPointConfiguration) PopulateExtensibilityPoint() error
func (*ExtensibilityPointConfiguration) ValidateExtensibilityPoint ¶
func (e *ExtensibilityPointConfiguration) ValidateExtensibilityPoint() error
type GlobalConfiguration ¶
type GlobalConfiguration struct { API APIConfiguration DB DBConfiguration External ProviderConfiguration Logging LoggingConfig `envconfig:"LOG"` Profiler ProfilerConfig `envconfig:"PROFILER"` OperatorToken string `split_words:"true" required:"false"` Tracing TracingConfig Metrics MetricsConfig SMTP SMTPConfiguration RateLimitHeader string `split_words:"true"` RateLimitEmailSent float64 `split_words:"true" default:"30"` RateLimitSmsSent float64 `split_words:"true" default:"30"` RateLimitVerify float64 `split_words:"true" default:"30"` RateLimitTokenRefresh float64 `split_words:"true" default:"150"` RateLimitSso float64 `split_words:"true" default:"30"` RateLimitAnonymousUsers float64 `split_words:"true" default:"30"` RateLimitOtp float64 `split_words:"true" default:"30"` SiteURL string `json:"site_url" split_words:"true" required:"true"` URIAllowList []string `json:"uri_allow_list" split_words:"true"` URIAllowListMap map[string]glob.Glob Password PasswordConfiguration `json:"password"` JWT JWTConfiguration `json:"jwt"` Mailer MailerConfiguration `json:"mailer"` Sms SmsProviderConfiguration `json:"sms"` DisableSignup bool `json:"disable_signup" split_words:"true"` Hook HookConfiguration `json:"hook" split_words:"true"` Security SecurityConfiguration `json:"security"` Sessions SessionsConfiguration `json:"sessions"` MFA MFAConfiguration `json:"MFA"` SAML SAMLConfiguration `json:"saml"` CORS CORSConfiguration `json:"cors"` }
GlobalConfiguration holds all the configuration that applies to all instances.
func LoadGlobal ¶
func LoadGlobal(filename string) (*GlobalConfiguration, error)
func LoadGlobalFromEnv ¶
func LoadGlobalFromEnv() (*GlobalConfiguration, error)
LoadGlobalFromEnv will return a new *GlobalConfiguration value from the currently configured environment.
func (*GlobalConfiguration) ApplyDefaults ¶
func (config *GlobalConfiguration) ApplyDefaults() error
ApplyDefaults sets defaults for a GlobalConfiguration
func (*GlobalConfiguration) Validate ¶
func (c *GlobalConfiguration) Validate() error
Validate validates all of configuration.
type HIBPBloomConfiguration ¶
type HIBPBloomConfiguration struct { Enabled bool `json:"enabled"` Items uint `json:"items" default:"100000"` FalsePositives float64 `json:"false_positives" split_words:"true" default:"0.0000099"` }
HIBPBloomConfiguration configures a bloom cache for pwned passwords. Use this tool to gauge the Items and FalsePositives values: https://hur.st/bloomfilter
type HIBPConfiguration ¶
type HIBPConfiguration struct { Enabled bool `json:"enabled"` FailClosed bool `json:"fail_closed" split_words:"true"` UserAgent string `json:"user_agent" split_words:"true" default:"https://github.com/supabase/gotrue"` Bloom HIBPBloomConfiguration `json:"bloom"` }
type HTTPHookSecrets ¶
type HTTPHookSecrets []string
func (*HTTPHookSecrets) Decode ¶
func (h *HTTPHookSecrets) Decode(value string) error
type HookConfiguration ¶
type HookConfiguration struct { MFAVerificationAttempt ExtensibilityPointConfiguration `json:"mfa_verification_attempt" split_words:"true"` PasswordVerificationAttempt ExtensibilityPointConfiguration `json:"password_verification_attempt" split_words:"true"` CustomAccessToken ExtensibilityPointConfiguration `json:"custom_access_token" split_words:"true"` SendEmail ExtensibilityPointConfiguration `json:"send_email" split_words:"true"` SendSMS ExtensibilityPointConfiguration `json:"send_sms" split_words:"true"` }
Moving away from the existing HookConfig so we can get a fresh start.
func (*HookConfiguration) Validate ¶
func (h *HookConfiguration) Validate() error
type JWTConfiguration ¶
type JWTConfiguration struct { Secret string `json:"secret" required:"true"` Exp int `json:"exp"` Aud string `json:"aud"` AdminGroupName string `json:"admin_group_name" split_words:"true"` AdminRoles []string `json:"admin_roles" split_words:"true"` DefaultGroupName string `json:"default_group_name" split_words:"true"` Issuer string `json:"issuer"` KeyID string `json:"key_id" split_words:"true"` Keys JwtKeysDecoder `json:"keys"` ValidMethods []string `json:"-"` }
JWTConfiguration holds all the JWT related configuration.
type JwtKeysDecoder ¶
func (*JwtKeysDecoder) Decode ¶
func (j *JwtKeysDecoder) Decode(value string) error
Decode implements the Decoder interface
func (*JwtKeysDecoder) Validate ¶
func (j *JwtKeysDecoder) Validate() error
type LoggingConfig ¶
type LoggingConfig struct { Level string `mapstructure:"log_level" json:"log_level"` File string `mapstructure:"log_file" json:"log_file"` DisableColors bool `mapstructure:"disable_colors" split_words:"true" json:"disable_colors"` QuoteEmptyFields bool `mapstructure:"quote_empty_fields" split_words:"true" json:"quote_empty_fields"` TSFormat string `mapstructure:"ts_format" json:"ts_format"` Fields map[string]interface{} `mapstructure:"fields" json:"fields"` SQL string `mapstructure:"sql" json:"sql"` }
type MFAConfiguration ¶
type MFAConfiguration struct { ChallengeExpiryDuration float64 `json:"challenge_expiry_duration" default:"300" split_words:"true"` FactorExpiryDuration time.Duration `json:"factor_expiry_duration" default:"300s" split_words:"true"` RateLimitChallengeAndVerify float64 `split_words:"true" default:"15"` MaxEnrolledFactors float64 `split_words:"true" default:"10"` MaxVerifiedFactors int `split_words:"true" default:"10"` Phone PhoneFactorTypeConfiguration `split_words:"true"` TOTP TOTPFactorTypeConfiguration `split_words:"true"` WebAuthn MFAFactorTypeConfiguration `split_words:"true"` }
MFAConfiguration holds all the MFA related Configuration
type MailerConfiguration ¶
type MailerConfiguration struct { Autoconfirm bool `json:"autoconfirm"` AllowUnverifiedEmailSignIns bool `json:"allow_unverified_email_sign_ins" split_words:"true" default:"false"` Subjects EmailContentConfiguration `json:"subjects"` Templates EmailContentConfiguration `json:"templates"` URLPaths EmailContentConfiguration `json:"url_paths"` SecureEmailChangeEnabled bool `json:"secure_email_change_enabled" split_words:"true" default:"true"` OtpExp uint `json:"otp_exp" split_words:"true"` OtpLength int `json:"otp_length" split_words:"true"` }
type MessagebirdProviderConfiguration ¶
type MessagebirdProviderConfiguration struct { AccessKey string `json:"access_key" split_words:"true"` Originator string `json:"originator" split_words:"true"` }
func (*MessagebirdProviderConfiguration) Validate ¶
func (t *MessagebirdProviderConfiguration) Validate() error
type MetricsConfig ¶
type MetricsConfig struct { Enabled bool Exporter MetricsExporter `default:"opentelemetry"` // ExporterProtocol is the OTEL_EXPORTER_OTLP_PROTOCOL env variable, // only available when exporter is opentelemetry. See: // https://github.com/open-telemetry/opentelemetry-specification/blob/main/specification/protocol/exporter.md ExporterProtocol string `default:"http/protobuf" envconfig:"OTEL_EXPORTER_OTLP_PROTOCOL"` PrometheusListenHost string `default:"0.0.0.0" envconfig:"OTEL_EXPORTER_PROMETHEUS_HOST"` PrometheusListenPort string `default:"9100" envconfig:"OTEL_EXPORTER_PROMETHEUS_PORT"` }
func (MetricsConfig) Validate ¶
func (mc MetricsConfig) Validate() error
type MetricsExporter ¶
type MetricsExporter = string
const ( Prometheus MetricsExporter = "prometheus" OpenTelemetryMetrics MetricsExporter = "opentelemetry" )
type OAuthProviderConfiguration ¶
type OAuthProviderConfiguration struct { ClientID []string `json:"client_id" split_words:"true"` Secret string `json:"secret"` RedirectURI string `json:"redirect_uri" split_words:"true"` URL string `json:"url"` ApiURL string `json:"api_url" split_words:"true"` Enabled bool `json:"enabled"` SkipNonceCheck bool `json:"skip_nonce_check" split_words:"true"` }
OAuthProviderConfiguration holds all config related to external account providers.
func (*OAuthProviderConfiguration) ValidateOAuth ¶
func (o *OAuthProviderConfiguration) ValidateOAuth() error
type PasswordConfiguration ¶
type PasswordConfiguration struct { MinLength int `json:"min_length" split_words:"true"` RequiredCharacters PasswordRequiredCharacters `json:"required_characters" split_words:"true"` HIBP HIBPConfiguration `json:"hibp"` }
type PasswordRequiredCharacters ¶
type PasswordRequiredCharacters []string
func (*PasswordRequiredCharacters) Decode ¶
func (v *PasswordRequiredCharacters) Decode(value string) error
type PhoneFactorTypeConfiguration ¶
type PhoneFactorTypeConfiguration struct { // Default to false in order to ensure Phone MFA is opt-in MFAFactorTypeConfiguration OtpLength int `json:"otp_length" split_words:"true"` SMSTemplate *template.Template `json:"-"` MaxFrequency time.Duration `json:"max_frequency" split_words:"true"` Template string `json:"template"` }
type PhoneProviderConfiguration ¶
type PhoneProviderConfiguration struct {
Enabled bool `json:"enabled" default:"false"`
}
type ProfilerConfig ¶
type ProviderConfiguration ¶
type ProviderConfiguration struct { AnonymousUsers AnonymousProviderConfiguration `json:"anonymous_users" split_words:"true"` Apple OAuthProviderConfiguration `json:"apple"` Azure OAuthProviderConfiguration `json:"azure"` Bitbucket OAuthProviderConfiguration `json:"bitbucket"` Discord OAuthProviderConfiguration `json:"discord"` Facebook OAuthProviderConfiguration `json:"facebook"` Figma OAuthProviderConfiguration `json:"figma"` Fly OAuthProviderConfiguration `json:"fly"` Github OAuthProviderConfiguration `json:"github"` Gitlab OAuthProviderConfiguration `json:"gitlab"` Google OAuthProviderConfiguration `json:"google"` Kakao OAuthProviderConfiguration `json:"kakao"` Notion OAuthProviderConfiguration `json:"notion"` Keycloak OAuthProviderConfiguration `json:"keycloak"` Linkedin OAuthProviderConfiguration `json:"linkedin"` LinkedinOIDC OAuthProviderConfiguration `json:"linkedin_oidc" envconfig:"LINKEDIN_OIDC"` Spotify OAuthProviderConfiguration `json:"spotify"` Slack OAuthProviderConfiguration `json:"slack"` SlackOIDC OAuthProviderConfiguration `json:"slack_oidc" envconfig:"SLACK_OIDC"` Twitter OAuthProviderConfiguration `json:"twitter"` Twitch OAuthProviderConfiguration `json:"twitch"` VercelMarketplace OAuthProviderConfiguration `json:"vercel_marketplace" split_words:"true"` WorkOS OAuthProviderConfiguration `json:"workos"` Email EmailProviderConfiguration `json:"email"` Phone PhoneProviderConfiguration `json:"phone"` Zoom OAuthProviderConfiguration `json:"zoom"` IosBundleId string `json:"ios_bundle_id" split_words:"true"` RedirectURL string `json:"redirect_url"` AllowedIdTokenIssuers []string `json:"allowed_id_token_issuers" split_words:"true"` FlowStateExpiryDuration time.Duration `json:"flow_state_expiry_duration" split_words:"true"` }
type SAMLConfiguration ¶
type SAMLConfiguration struct { Enabled bool `json:"enabled"` PrivateKey string `json:"-" split_words:"true"` AllowEncryptedAssertions bool `json:"allow_encrypted_assertions" split_words:"true"` RelayStateValidityPeriod time.Duration `json:"relay_state_validity_period" split_words:"true"` RSAPrivateKey *rsa.PrivateKey `json:"-"` RSAPublicKey *rsa.PublicKey `json:"-"` Certificate *x509.Certificate `json:"-"` ExternalURL string `json:"external_url,omitempty" split_words:"true"` RateLimitAssertion float64 `default:"15" split_words:"true"` }
SAMLConfiguration holds configuration for native SAML support.
func (*SAMLConfiguration) PopulateFields ¶
func (c *SAMLConfiguration) PopulateFields(externalURL string) error
PopulateFields fills the configuration details based off the provided parameters.
func (*SAMLConfiguration) Validate ¶
func (c *SAMLConfiguration) Validate() error
type SMTPConfiguration ¶
type SMTPConfiguration struct { MaxFrequency time.Duration `json:"max_frequency" split_words:"true"` Host string `json:"host"` Port int `json:"port,omitempty" default:"587"` User string `json:"user"` Pass string `json:"pass,omitempty"` AdminEmail string `json:"admin_email" split_words:"true"` SenderName string `json:"sender_name" split_words:"true"` }
func (*SMTPConfiguration) Validate ¶
func (c *SMTPConfiguration) Validate() error
type SecurityConfiguration ¶
type SecurityConfiguration struct { Captcha CaptchaConfiguration `json:"captcha"` RefreshTokenRotationEnabled bool `json:"refresh_token_rotation_enabled" split_words:"true" default:"true"` RefreshTokenReuseInterval int `json:"refresh_token_reuse_interval" split_words:"true"` UpdatePasswordRequireReauthentication bool `json:"update_password_require_reauthentication" split_words:"true"` ManualLinkingEnabled bool `json:"manual_linking_enabled" split_words:"true" default:"false"` DBEncryption DatabaseEncryptionConfiguration `json:"database_encryption" split_words:"true"` }
func (*SecurityConfiguration) Validate ¶
func (c *SecurityConfiguration) Validate() error
type SessionsConfiguration ¶
type SessionsConfiguration struct { Timebox *time.Duration `json:"timebox"` InactivityTimeout *time.Duration `json:"inactivity_timeout,omitempty" split_words:"true"` SinglePerUser bool `json:"single_per_user" split_words:"true"` Tags []string `json:"tags,omitempty"` }
func (*SessionsConfiguration) Validate ¶
func (c *SessionsConfiguration) Validate() error
type SmsProviderConfiguration ¶
type SmsProviderConfiguration struct { Autoconfirm bool `json:"autoconfirm"` MaxFrequency time.Duration `json:"max_frequency" split_words:"true"` OtpExp uint `json:"otp_exp" split_words:"true"` OtpLength int `json:"otp_length" split_words:"true"` Provider string `json:"provider"` Template string `json:"template"` TestOTP map[string]string `json:"test_otp" split_words:"true"` TestOTPValidUntil Time `json:"test_otp_valid_until" split_words:"true"` SMSTemplate *template.Template `json:"-"` Twilio TwilioProviderConfiguration `json:"twilio"` TwilioVerify TwilioVerifyProviderConfiguration `json:"twilio_verify" split_words:"true"` Messagebird MessagebirdProviderConfiguration `json:"messagebird"` Textlocal TextlocalProviderConfiguration `json:"textlocal"` Vonage VonageProviderConfiguration `json:"vonage"` }
func (*SmsProviderConfiguration) GetTestOTP ¶
func (*SmsProviderConfiguration) IsTwilioVerifyProvider ¶
func (t *SmsProviderConfiguration) IsTwilioVerifyProvider() bool
type TextlocalProviderConfiguration ¶
type TextlocalProviderConfiguration struct { ApiKey string `json:"api_key" split_words:"true"` Sender string `json:"sender" split_words:"true"` }
func (*TextlocalProviderConfiguration) Validate ¶
func (t *TextlocalProviderConfiguration) Validate() error
type Time ¶
Time is used to represent timestamps in the configuration, as envconfig has trouble parsing empty strings, due to time.Time.UnmarshalText().
func (*Time) UnmarshalText ¶
type TracingConfig ¶
type TracingConfig struct { Enabled bool Exporter TracingExporter `default:"opentelemetry"` // ExporterProtocol is the OTEL_EXPORTER_OTLP_PROTOCOL env variable, // only available when exporter is opentelemetry. See: // https://github.com/open-telemetry/opentelemetry-specification/blob/main/specification/protocol/exporter.md ExporterProtocol string `default:"http/protobuf" envconfig:"OTEL_EXPORTER_OTLP_PROTOCOL"` // Host is the host of the OpenTracing collector. Host string // Port is the port of the OpenTracing collector. Port string // ServiceName is the service name to use with OpenTracing. ServiceName string `default:"gotrue" split_words:"true"` // Tags are the tags to associate with OpenTracing. Tags map[string]string }
func (*TracingConfig) Validate ¶
func (tc *TracingConfig) Validate() error
type TracingExporter ¶
type TracingExporter = string
const (
OpenTelemetryTracing TracingExporter = "opentelemetry"
)
type TwilioProviderConfiguration ¶
type TwilioProviderConfiguration struct { AccountSid string `json:"account_sid" split_words:"true"` AuthToken string `json:"auth_token" split_words:"true"` MessageServiceSid string `json:"message_service_sid" split_words:"true"` ContentSid string `json:"content_sid" split_words:"true"` }
func (*TwilioProviderConfiguration) Validate ¶
func (t *TwilioProviderConfiguration) Validate() error
type TwilioVerifyProviderConfiguration ¶
type TwilioVerifyProviderConfiguration struct { AccountSid string `json:"account_sid" split_words:"true"` AuthToken string `json:"auth_token" split_words:"true"` MessageServiceSid string `json:"message_service_sid" split_words:"true"` }
func (*TwilioVerifyProviderConfiguration) Validate ¶
func (t *TwilioVerifyProviderConfiguration) Validate() error
type VonageProviderConfiguration ¶
type VonageProviderConfiguration struct { ApiKey string `json:"api_key" split_words:"true"` ApiSecret string `json:"api_secret" split_words:"true"` From string `json:"from" split_words:"true"` }
func (*VonageProviderConfiguration) Validate ¶
func (t *VonageProviderConfiguration) Validate() error