<%# locals: (sso_provider:) %> <% if sso_provider.errors.any? %>
<%= icon "alert-circle", class: "w-5 h-5 text-destructive mr-2 shrink-0" %>

<%= pluralize(sso_provider.errors.count, "error") %> prohibited this provider from being saved:

    <% sso_provider.errors.full_messages.each do |message| %>
  • <%= message %>
  • <% end %>
<% end %> <%= styled_form_with model: [:admin, sso_provider], class: "space-y-6", data: { controller: "admin-sso-form" } do |form| %>

Basic Information

<%= form.select :strategy, options_for_select([ ["OpenID Connect", "openid_connect"], ["SAML 2.0", "saml"], ["Google OAuth2", "google_oauth2"], ["GitHub", "github"] ], sso_provider.strategy), { label: "Strategy" }, { data: { action: "change->admin-sso-form#toggleFields" } } %> <%= form.text_field :name, label: "Name", placeholder: "e.g., keycloak, authentik", required: true, data: { action: "input->admin-sso-form#updateCallbackUrl" } %>

Unique identifier (lowercase, numbers, underscores only)

<%= form.text_field :label, label: "Button Label", placeholder: "e.g., Sign in with Keycloak", required: true %>
<%= form.text_field :icon, label: "Icon (optional)", placeholder: "e.g., key, shield" %>

Lucide icon name for the login button

<%= t("admin.sso_providers.form.enabled_label") %>

<%= t("admin.sso_providers.form.enabled_help") %>

<%= form.toggle :enabled %>

OAuth/OIDC Configuration

"> <%= form.text_field :issuer, label: "Issuer URL", placeholder: "https://your-idp.example.com/realms/your-realm", data: { action: "blur->admin-sso-form#validateIssuer" } %>

OIDC issuer URL (validates .well-known/openid-configuration)

<%= form.text_field :client_id, label: "Client ID", placeholder: "your-client-id", required: true %> <%= form.password_field :client_secret, label: "Client Secret", placeholder: sso_provider.persisted? ? "••••••••" : "your-client-secret", required: !sso_provider.persisted? %> <% if sso_provider.persisted? %>

Leave blank to keep existing secret

<% end %>
">
<%= "#{request.base_url}/auth/#{sso_provider.name.presence || 'PROVIDER_NAME'}/callback" %>

Configure this URL in your identity provider

">

<%= t("admin.sso_providers.form.saml_configuration") %>

" class="w-full px-3 py-2 border border-primary rounded-lg text-sm" placeholder="https://idp.example.com/metadata" autocomplete="off">

<%= t("admin.sso_providers.form.idp_metadata_url_help") %>

<%= t("admin.sso_providers.form.manual_saml_config") %>

<%= t("admin.sso_providers.form.manual_saml_help") %>

" class="w-full px-3 py-2 border border-primary rounded-lg text-sm" placeholder="https://idp.example.com/sso" autocomplete="off">
" class="w-full px-3 py-2 border border-primary rounded-lg text-sm" placeholder="https://idp.example.com/slo (optional)" autocomplete="off">

<%= t("admin.sso_providers.form.idp_certificate_help") %>

" class="w-full px-3 py-2 border border-primary rounded-lg text-sm font-mono" placeholder="AB:CD:EF:..." autocomplete="off">
<%= "#{request.base_url}/auth/#{sso_provider.name.presence || 'PROVIDER_NAME'}/callback" %>

Configure this URL as the Assertion Consumer Service URL in your IdP

<%= t("admin.sso_providers.form.provisioning_title") %>

<%= form.select "settings[default_role]", options_for_select([ [t("admin.sso_providers.form.role_guest", default: "Guest"), "guest"], [t("admin.sso_providers.form.role_member"), "member"], [t("admin.sso_providers.form.role_admin"), "admin"], [t("admin.sso_providers.form.role_super_admin"), "super_admin"] ], sso_provider.settings&.dig("default_role").to_s.presence || "member"), { label: t("admin.sso_providers.form.default_role_label"), include_blank: false } %>

<%= t("admin.sso_providers.form.default_role_help") %>

<%= t("admin.sso_providers.form.role_mapping_title") %>

<%= t("admin.sso_providers.form.role_mapping_help") %>

" class="w-full px-3 py-2 border border-primary rounded-lg text-sm" placeholder="Platform-Admins, IdP-Superusers" autocomplete="off">

<%= t("admin.sso_providers.form.groups_help") %>

" class="w-full px-3 py-2 border border-primary rounded-lg text-sm" placeholder="Team-Leads, Managers" autocomplete="off">
" class="w-full px-3 py-2 border border-primary rounded-lg text-sm" placeholder="* (all groups)" autocomplete="off">
" class="w-full px-3 py-2 border border-primary rounded-lg text-sm" placeholder="Early-Access-Guests" autocomplete="off">
">

<%= t("admin.sso_providers.form.advanced_title") %>

<%= form.text_field "settings[scopes]", label: t("admin.sso_providers.form.scopes_label"), value: sso_provider.settings&.dig("scopes"), placeholder: "openid email profile groups" %>

<%= t("admin.sso_providers.form.scopes_help") %>

<%= form.select "settings[prompt]", options_for_select([ [t("admin.sso_providers.form.prompt_default"), ""], [t("admin.sso_providers.form.prompt_login"), "login"], [t("admin.sso_providers.form.prompt_consent"), "consent"], [t("admin.sso_providers.form.prompt_select_account"), "select_account"], [t("admin.sso_providers.form.prompt_none"), "none"] ], sso_provider.settings&.dig("prompt")), { label: t("admin.sso_providers.form.prompt_label"), include_blank: false } %>

<%= t("admin.sso_providers.form.prompt_help") %>

<% if sso_provider.persisted? %> <% end %>
<%= link_to "Cancel", admin_sso_providers_path, class: "px-4 py-2 text-sm font-medium text-secondary hover:text-primary" %> <%= form.submit sso_provider.persisted? ? "Update Provider" : "Create Provider", class: "px-4 py-2 bg-primary text-inverse rounded-lg text-sm font-medium hover:bg-primary/90" %>
<% end %>