SSO Provider Management#
SSO provider management in Sure covers how the application loads, stores, and registers authentication providers (OIDC, Google OAuth2, GitHub OAuth, SAML) into OmniAuth at boot time. The system supports two storage backends — a YAML config file and a database model — switchable via a feature flag.
Architecture Overview#
Components#
ProviderLoader — app/services/provider_loader.rb #
The single entry point for loading provider config at boot. ProviderLoader.load_providers checks a 5-minute Rails cache (sso_providers_config key) before loading, and delegates to either load_from_database or load_from_yaml. Database errors and empty result sets both fall back to YAML . Call ProviderLoader.clear_cache after modifying providers in the admin UI.
FeatureFlags.db_sso_providers? — lib/feature_flags.rb #
Controls which backend is used :
- Reads
AUTH_PROVIDERS_SOURCEenv var first ("db"→ database, anything else → YAML). - In production with no env var set, defaults to YAML to avoid querying the
sso_providerstable before migrations run. - On non-production self-hosted deployments, defaults to
"db". - In test environments, always returns
false.
SsoProvider model — app/models/sso_provider.rb #
ActiveRecord model backed by the sso_providers table (UUID primary key, JSONB settings column). Supported strategies are validated to openid_connect, google_oauth2, github, saml . Provider names must be lowercase alphanumeric + underscores and are unique .
to_omniauth_config serializes a record into a hash consumed by the OmniAuth initializer. client_secret is encrypted at rest via ActiveRecord Encryption when available , guarded by the Encryptable concern. SslConfigurable is extended for OIDC discovery HTTP calls.
Strategy-specific validations enforce required fields:
- OIDC:
issuer(valid URL),client_id,client_secret - OAuth (Google/GitHub):
client_id,client_secret - SAML: either
idp_metadata_urloridp_sso_url+ certificate
config/initializers/omniauth.rb — OmniAuth registration #
After ProviderLoader.load_providers returns the config array, the initializer iterates and registers each strategy :
| Strategy | Key behavior |
|---|---|
openid_connect | Delegates option-building to Oidc::ProviderOptionsBuilder.call; sets oidc_enabled = true on success |
google_oauth2 | Falls back to GOOGLE_OAUTH_CLIENT_ID / GOOGLE_OAUTH_CLIENT_SECRET env vars |
github | Falls back to GITHUB_CLIENT_ID / GITHUB_CLIENT_SECRET env vars |
saml | Builds options from settings JSONB; supports metadata URL or manual IdP config with optional SLO |
Successfully registered providers are appended to Rails.configuration.x.auth.sso_providers , which is initialized as [] in config/initializers/auth.rb.
config/auth.yml — YAML backend #
The fallback (and default in production) config source. Loaded by Rails.application.config_for(:auth). The providers array under this file feeds directly into the same hash format as to_omniauth_config.
Key Relationships#
- Boot sequence:
auth.rbinitializer runs first (sets upRails.configuration.x.auth), thenomniauth.rbcallsProviderLoaderand populatessso_providers. - Cache invalidation: Updating providers in the admin must call
ProviderLoader.clear_cache; otherwise changes won't be reflected until the 5-minute TTL expires. - OIDC specifics are handled downstream by
Oidc::ProviderOptionsBuilder— that class is the place to look for PKCE, scope, and discovery configuration, not here.