Packages

phoenix_kit

1.7.172
1.7.208 1.7.207 1.7.206 1.7.205 1.7.204 1.7.203 1.7.202 1.7.201 1.7.200 1.7.199 1.7.198 1.7.197 1.7.196 1.7.194 1.7.193 1.7.192 1.7.191 1.7.190 1.7.189 1.7.187 1.7.186 1.7.185 1.7.184 1.7.183 1.7.182 1.7.181 1.7.180 1.7.179 1.7.178 1.7.177 1.7.176 1.7.175 1.7.174 1.7.173 1.7.172 1.7.171 1.7.170 1.7.169 1.7.168 1.7.167 1.7.166 1.7.165 1.7.164 1.7.162 1.7.161 1.7.160 1.7.159 1.7.157 1.7.156 1.7.155 1.7.154 1.7.153 1.7.152 1.7.151 1.7.150 1.7.149 1.7.146 1.7.145 1.7.144 1.7.143 1.7.138 1.7.133 1.7.132 1.7.131 1.7.130 1.7.128 1.7.126 1.7.125 1.7.121 1.7.120 1.7.119 1.7.118 1.7.117 1.7.116 1.7.115 1.7.114 1.7.113 1.7.112 1.7.111 1.7.110 1.7.109 1.7.108 1.7.107 1.7.106 1.7.105 1.7.104 1.7.103 1.7.102 1.7.101 1.7.100 1.7.99 1.7.98 1.7.97 1.7.96 1.7.95 1.7.94 1.7.93 1.7.92 1.7.91 1.7.90 1.7.89 1.7.88 1.7.87 1.7.86 1.7.85 1.7.84 1.7.83 1.7.82 1.7.81 1.7.80 1.7.79 1.7.78 1.7.77 1.7.76 1.7.75 1.7.74 1.7.71 1.7.70 1.7.69 1.7.66 1.7.65 1.7.64 1.7.63 1.7.62 1.7.61 1.7.59 1.7.58 1.7.57 1.7.56 1.7.55 1.7.54 1.7.53 1.7.52 1.7.51 1.7.49 1.7.44 1.7.43 1.7.42 1.7.41 1.7.39 1.7.38 1.7.37 1.7.36 1.7.34 1.7.33 1.7.31 1.7.30 1.7.29 1.7.28 1.7.27 1.7.26 1.7.25 1.7.24 1.7.23 1.7.22 1.7.21 1.7.20 1.7.19 1.7.18 1.7.17 1.7.16 1.7.15 1.7.14 1.7.13 1.7.12 1.7.11 1.7.10 1.7.9 1.7.8 1.7.7 1.7.6 1.7.5 1.7.4 1.7.3 1.7.2 1.7.1 1.7.0 1.6.20 1.6.19 1.6.18 1.6.17 1.6.16 1.6.15 1.6.14 1.6.13 1.6.12 1.6.11 1.6.10 1.6.9 1.6.8 1.6.7 1.6.6 1.6.5 1.6.4 1.6.3 1.5.2 1.5.1 1.5.0 1.4.9 1.4.8 1.4.7 1.4.6 1.4.5 1.4.4 1.4.3 1.4.2 1.4.1 1.4.0 1.3.2 1.3.1 1.3.0 1.2.10 1.2.9 1.2.8 1.2.7 1.2.5 1.2.4 1.2.2 1.2.1 1.2.0 1.1.0 1.0.0

A foundation for building Elixir Phoenix apps — SaaS, social networks, ERP systems, marketplaces, and more

Current section

Files

Jump to
phoenix_kit lib phoenix_kit_web live settings authorization.html.heex
Raw

lib/phoenix_kit_web/live/settings/authorization.html.heex

<PhoenixKitWeb.Components.LayoutWrapper.app_layout
socket={@socket}
flash={@flash}
phoenix_kit_current_scope={assigns[:phoenix_kit_current_scope]}
page_title={gettext("Authorization Settings")}
page_subtitle={gettext("Manage login page branding and authentication methods")}
current_path={@url_path}
project_title={@project_title}
current_locale={@current_locale}
>
<div class="container flex flex-col mx-auto px-4 py-6">
<%!-- Settings Form --%>
<div class="card bg-base-100 shadow-xl">
<div class="card-body">
<h2 class="card-title text-xl mb-6">{gettext("Authorization Configuration")}</h2>
<.form
:let={_form}
for={@changeset}
id="authorization_settings_form"
phx-submit="save_settings"
phx-change="validate_settings"
class="space-y-6"
>
<%!-- Hidden fields for required settings from other pages --%>
<%!-- General Settings --%>
<input
type="hidden"
name="settings[project_title]"
value={@saved_settings["project_title"]}
/>
<input
type="hidden"
name="settings[site_url]"
value={@saved_settings["site_url"]}
/>
<input
type="hidden"
name="settings[week_start_day]"
value={@saved_settings["week_start_day"]}
/>
<input
type="hidden"
name="settings[time_zone]"
value={@saved_settings["time_zone"]}
/>
<input
type="hidden"
name="settings[date_format]"
value={@saved_settings["date_format"]}
/>
<input
type="hidden"
name="settings[time_format]"
value={@saved_settings["time_format"]}
/>
<%!-- Users Settings --%>
<input
type="hidden"
name="settings[allow_registration]"
value={@saved_settings["allow_registration"]}
/>
<input
type="hidden"
name="settings[new_user_default_role]"
value={@saved_settings["new_user_default_role"]}
/>
<input
type="hidden"
name="settings[new_user_default_status]"
value={@saved_settings["new_user_default_status"]}
/>
<input
type="hidden"
name="settings[track_registration_geolocation]"
value={@saved_settings["track_registration_geolocation"]}
/>
<%!-- Login Page Branding --%>
<div class="divider text-sm text-base-content/50">
{gettext("Login Page Branding")}
</div>
<div class="grid grid-cols-1 md:grid-cols-2 gap-6">
<div class="form-control w-full">
<label class="label">
<span class="label-text text-base font-medium">
{gettext("Background Image (Desktop)")}
</span>
</label>
<input
type="hidden"
name="settings[auth_background_image_file_uuid]"
value={@settings["auth_background_image_file_uuid"]}
/>
<%= if @settings["auth_background_image_file_uuid"] != "" do %>
<div class="flex items-center gap-3 p-2 bg-base-200 rounded-lg">
<img
src={
signed_preview_url(@settings["auth_background_image_file_uuid"], "medium")
}
alt="Background preview"
class="h-16 w-24 object-cover rounded"
/>
<button
type="button"
class="btn btn-ghost btn-sm"
phx-click="clear_branding_image"
phx-value-target="background"
>
{gettext("Remove")}
</button>
</div>
<% else %>
<button
type="button"
class="btn btn-outline btn-sm w-fit"
phx-click="open_media_selector"
phx-value-target="background"
>
{gettext("Select Image")}
</button>
<% end %>
<div class="label">
<span class="label-text-alt text-xs text-base-content/50">
{gettext(
"Background image for auth pages on desktop screens (wider than 768px)."
)}
</span>
</div>
</div>
<div class="form-control w-full">
<label class="label">
<span class="label-text text-base font-medium">
{gettext("Background Image (Mobile)")}
</span>
</label>
<input
type="hidden"
name="settings[auth_background_image_mobile_file_uuid]"
value={@settings["auth_background_image_mobile_file_uuid"]}
/>
<%= if @settings["auth_background_image_mobile_file_uuid"] != "" do %>
<div class="flex items-center gap-3 p-2 bg-base-200 rounded-lg">
<img
src={
signed_preview_url(
@settings["auth_background_image_mobile_file_uuid"],
"medium"
)
}
alt="Mobile background preview"
class="h-16 w-24 object-cover rounded"
/>
<button
type="button"
class="btn btn-ghost btn-sm"
phx-click="clear_branding_image"
phx-value-target="background_mobile"
>
{gettext("Remove")}
</button>
</div>
<% else %>
<button
type="button"
class="btn btn-outline btn-sm w-fit"
phx-click="open_media_selector"
phx-value-target="background_mobile"
>
{gettext("Select Image")}
</button>
<% end %>
<div class="label">
<span class="label-text-alt text-xs text-base-content/50">
{gettext(
"Background image for auth pages on mobile screens (768px and below). Falls back to desktop image if not set."
)}
</span>
</div>
</div>
</div>
<div class="form-control w-full">
<label class="label">
<span class="label-text text-base font-medium">
{gettext("Background Color")}
</span>
</label>
<input
name="settings[auth_background_color]"
type="text"
value={@settings["auth_background_color"]}
class="input input-bordered w-full focus:input-primary"
placeholder={gettext("#1a1a2e or linear-gradient(135deg, #667eea, #764ba2)")}
phx-debounce="500"
/>
<div class="label">
<span class="label-text-alt text-xs text-base-content/50">
{gettext(
"CSS color or gradient for auth page background. Ignored if a background image is set."
)}
</span>
</div>
</div>
<%!-- Authentication Methods Setting --%>
<div class="form-control w-full">
<label class="label">
<span class="label-text text-base font-medium">
{gettext("Authentication Methods")}
</span>
<span class="label-text-alt text-sm text-base-content/60">
{gettext("Control available login/registration methods")}
</span>
</label>
<%!-- Magic Link Methods --%>
<div class="mb-3">
<div class="text-sm font-semibold text-base-content/70 mb-2">
{gettext("Magic Link")}
</div>
<div class="flex items-center gap-3 mb-2 ml-4">
<input
name="settings[magic_link_login_enabled]"
type="hidden"
value="false"
/>
<input
name="settings[magic_link_login_enabled]"
type="checkbox"
value="true"
checked={@settings["magic_link_login_enabled"] == "true"}
class="checkbox checkbox-primary"
/>
<span class="label-text">{gettext("Enable Magic Link for login")}</span>
</div>
<div class="flex items-center gap-3 ml-4">
<input
name="settings[magic_link_registration_enabled]"
type="hidden"
value="false"
/>
<input
name="settings[magic_link_registration_enabled]"
type="checkbox"
value="true"
checked={
@settings["magic_link_registration_enabled"] == "true" and
@settings["allow_registration"] == "true"
}
disabled={@settings["allow_registration"] != "true"}
class="checkbox checkbox-primary"
/>
<span class={[
"label-text",
@settings["allow_registration"] != "true" && "text-base-content/40"
]}>
{gettext("Enable Magic Link for registration")}
<%= if @settings["allow_registration"] != "true" do %>
<span class="text-xs italic">{gettext("(registration disabled)")}</span>
<% end %>
</span>
</div>
</div>
<%!-- OAuth Methods --%>
<div>
<div class="text-sm font-semibold text-base-content/70 mb-2">
{gettext("OAuth Providers")}
</div>
<div class="flex items-center gap-3 mb-2 ml-4">
<input name="settings[oauth_enabled]" type="hidden" value="false" />
<input
name="settings[oauth_enabled]"
type="checkbox"
value="true"
checked={@settings["oauth_enabled"] == "true"}
class="checkbox checkbox-primary"
/>
<span class="label-text font-semibold">
{gettext("Enable OAuth (Master Switch)")}
</span>
</div>
<%!-- Individual OAuth Providers (disabled if master is off) --%>
<div class={[
"ml-8 space-y-2",
if(@settings["oauth_enabled"] != "true", do: "opacity-50", else: "")
]}>
<div class="flex items-center gap-3">
<input
name="settings[oauth_google_enabled]"
type="hidden"
value="false"
/>
<input
name="settings[oauth_google_enabled]"
type="checkbox"
value="true"
checked={@settings["oauth_google_enabled"] == "true"}
class={[
"checkbox checkbox-primary",
if(@settings["oauth_enabled"] != "true",
do: "pointer-events-none",
else: ""
)
]}
/>
<span class="label-text">{gettext("Google Sign-In")}</span>
</div>
<div class="flex items-center gap-3">
<input name="settings[oauth_apple_enabled]" type="hidden" value="false" />
<input
name="settings[oauth_apple_enabled]"
type="checkbox"
value="true"
checked={@settings["oauth_apple_enabled"] == "true"}
class={[
"checkbox checkbox-primary",
if(@settings["oauth_enabled"] != "true",
do: "pointer-events-none",
else: ""
)
]}
/>
<span class="label-text">{gettext("Apple Sign-In")}</span>
</div>
<div class="flex items-center gap-3">
<input
name="settings[oauth_github_enabled]"
type="hidden"
value="false"
/>
<input
name="settings[oauth_github_enabled]"
type="checkbox"
value="true"
checked={@settings["oauth_github_enabled"] == "true"}
class={[
"checkbox checkbox-primary",
if(@settings["oauth_enabled"] != "true",
do: "pointer-events-none",
else: ""
)
]}
/>
<span class="label-text">{gettext("GitHub Sign-In")}</span>
</div>
<div class="flex items-center gap-3">
<input
name="settings[oauth_facebook_enabled]"
type="hidden"
value="false"
/>
<input
name="settings[oauth_facebook_enabled]"
type="checkbox"
value="true"
checked={@settings["oauth_facebook_enabled"] == "true"}
class={[
"checkbox checkbox-primary",
if(@settings["oauth_enabled"] != "true",
do: "pointer-events-none",
else: ""
)
]}
/>
<span class="label-text">{gettext("Facebook Sign-In")}</span>
</div>
</div>
</div>
<%!-- OAuth Provider Credential Forms --%>
<%= if @settings["oauth_enabled"] == "true" do %>
<%!-- Google OAuth Credentials --%>
<div class={[
if(@settings["oauth_google_enabled"] != "true", do: "hidden", else: "")
]}>
<div class="card bg-base-200 p-4 mt-3">
<h3 class="font-semibold mb-3 flex items-center gap-2">
<PhoenixKitWeb.Components.Core.Icons.icon_google class="h-5 w-5" />
{gettext("Google OAuth Credentials")}
</h3>
<div class="grid grid-cols-1 md:grid-cols-2 gap-3">
<div class="form-control">
<label class="label">
<span class="label-text">{gettext("Client ID")}</span>
</label>
<input
type="text"
name="settings[oauth_google_client_id]"
value={@settings["oauth_google_client_id"] || ""}
placeholder={gettext("Your Google OAuth Client ID")}
class="input input-bordered"
/>
</div>
<div class="form-control">
<label class="label">
<span class="label-text">{gettext("Client Secret")}</span>
</label>
<input
type="password"
name="settings[oauth_google_client_secret]"
value={@settings["oauth_google_client_secret"] || ""}
placeholder={gettext("Your Google OAuth Client Secret")}
class="input input-bordered"
/>
</div>
</div>
<button
type="button"
phx-click="test_oauth"
phx-value-provider="google"
class="btn btn-sm btn-outline mt-3 w-fit"
>
{gettext("Test Credentials")}
</button>
<%!-- Google OAuth Setup Instructions --%>
<div class="collapse collapse-arrow bg-base-200 mt-4">
<input type="checkbox" class="peer" />
<div class="collapse-title text-sm font-medium">
{gettext("Setup Instructions")}
</div>
<div class="collapse-content text-sm space-y-4">
<%!-- Callback URL Section --%>
<div class="bg-base-100 border border-base-300 rounded-lg p-4">
<div class="flex items-start gap-3">
<.icon
name="hero-information-circle"
class="stroke-current shrink-0 h-5 w-5 text-info mt-0.5"
/>
<div class="flex-1 min-w-0">
<div class="text-sm font-semibold text-base-content mb-2">
{gettext("Callback URL")}
</div>
<div class="flex items-center gap-2">
<code class="flex-1 px-3 py-2 bg-base-200 text-base-content border border-base-300 rounded font-mono text-xs break-all">
{get_oauth_callback_url(@settings, "google")}
</code>
<button
type="button"
class="btn btn-sm btn-square btn-outline"
onclick={"navigator.clipboard.writeText('#{get_oauth_callback_url(@settings, "google")}')"}
title={gettext("Copy to clipboard")}
>
<.icon name="hero-clipboard" class="h-4 w-4" />
</button>
</div>
<div class="text-xs text-base-content/60 mt-2">
{gettext("Copy this URL to Google Cloud Console")}
</div>
</div>
</div>
</div>
<%!-- Step-by-step Instructions --%>
<div class="space-y-3">
<ol class="list-decimal list-inside space-y-2 text-base-content/80">
<li>
{gettext("Visit")}
<a
href="https://console.cloud.google.com/apis/credentials"
target="_blank"
class="link link-primary"
>
Google Cloud Console
</a>
</li>
<li>{gettext("Create project or select existing one")}</li>
<li>
{gettext("Go to")} <strong>Credentials</strong>
<strong>Create Credentials</strong>
<strong>OAuth client ID</strong>
</li>
<li>
{gettext("Select")}
<strong>Web application</strong> {gettext("type")}
</li>
<li>
{gettext("Add callback URL above to")}
<strong>Authorized redirect URIs</strong>
</li>
<li>{gettext("Copy Client ID and Secret to fields above")}</li>
<li>
{gettext("Click")}
<strong>Test Credentials</strong> {gettext("to verify setup")}
</li>
</ol>
</div>
<%!-- Reverse Proxy Notice --%>
<div class="bg-base-200 border border-base-300 rounded-lg p-3 text-xs">
<div class="flex items-start gap-2">
<.icon
name="hero-information-circle"
class="h-4 w-4 text-info shrink-0 mt-0.5"
/>
<div class="text-base-content/80">
<strong class="text-base-content">
{gettext("Reverse Proxy Users:")}
</strong>
{gettext("If behind nginx/apache, ensure")}
<code class="px-1 py-0.5 bg-base-300 text-base-content rounded text-xs">
X-Forwarded-Proto
</code>
{gettext("header is set to")}
<code class="px-1 py-0.5 bg-base-300 text-base-content rounded text-xs">
https
</code>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
<%!-- Apple OAuth Credentials --%>
<div class={[
if(@settings["oauth_apple_enabled"] != "true", do: "hidden", else: "")
]}>
<div class="card bg-base-200 p-4 mt-3">
<h3 class="font-semibold mb-3 flex items-center gap-2">
<PhoenixKitWeb.Components.Core.Icons.icon_apple class="h-5 w-5" />
{gettext("Apple OAuth Credentials")}
</h3>
<div class="grid grid-cols-1 md:grid-cols-2 gap-3">
<div class="form-control">
<label class="label">
<span class="label-text">{gettext("Client ID")}</span>
</label>
<input
type="text"
name="settings[oauth_apple_client_id]"
value={@settings["oauth_apple_client_id"] || ""}
placeholder="com.yourapp.service"
class="input input-bordered"
/>
</div>
<div class="form-control">
<label class="label">
<span class="label-text">{gettext("Team ID")}</span>
</label>
<input
type="text"
name="settings[oauth_apple_team_id]"
value={@settings["oauth_apple_team_id"] || ""}
placeholder={gettext("Your Apple Team ID")}
class="input input-bordered"
/>
</div>
</div>
<div class="form-control mt-3">
<label class="label">
<span class="label-text">{gettext("Key ID")}</span>
</label>
<input
type="text"
name="settings[oauth_apple_key_id]"
value={@settings["oauth_apple_key_id"] || ""}
placeholder={gettext("Your Apple Key ID")}
class="input input-bordered"
/>
</div>
<div class="form-control mt-3">
<label class="label">
<span class="label-text">{gettext("Private Key")}</span>
</label>
<textarea
name="settings[oauth_apple_private_key]"
rows="5"
placeholder="-----BEGIN PRIVATE KEY-----&#10;Your Apple private key content&#10;-----END PRIVATE KEY-----"
class="textarea textarea-bordered font-mono text-xs"
>{@settings["oauth_apple_private_key"] || ""}</textarea>
</div>
<button
type="button"
phx-click="test_oauth"
phx-value-provider="apple"
class="btn btn-sm btn-outline mt-3 w-fit"
>
{gettext("Test Credentials")}
</button>
<%!-- Apple OAuth Setup Instructions --%>
<div class="collapse collapse-arrow bg-base-200 mt-4">
<input type="checkbox" class="peer" />
<div class="collapse-title text-sm font-medium">
{gettext("Setup Instructions")}
</div>
<div class="collapse-content text-sm space-y-4">
<%!-- Callback URL Section --%>
<div class="bg-base-100 border border-base-300 rounded-lg p-4">
<div class="flex items-start gap-3">
<.icon
name="hero-information-circle"
class="stroke-current shrink-0 h-5 w-5 text-info mt-0.5"
/>
<div class="flex-1 min-w-0">
<div class="text-sm font-semibold text-base-content mb-2">
{gettext("Callback URL")}
</div>
<div class="flex items-center gap-2">
<code class="flex-1 px-3 py-2 bg-base-200 text-base-content border border-base-300 rounded font-mono text-xs break-all">
{get_oauth_callback_url(@settings, "apple")}
</code>
<button
type="button"
class="btn btn-sm btn-square btn-outline"
onclick={"navigator.clipboard.writeText('#{get_oauth_callback_url(@settings, "apple")}')"}
title={gettext("Copy to clipboard")}
>
<.icon name="hero-clipboard" class="h-4 w-4" />
</button>
</div>
<div class="text-xs text-base-content/60 mt-2">
{gettext("Copy this URL to Apple Developer Console")}
</div>
</div>
</div>
</div>
<%!-- Step-by-step Instructions --%>
<div class="space-y-3">
<ol class="list-decimal list-inside space-y-2 text-base-content/80">
<li>
{gettext("Visit")}
<a
href="https://developer.apple.com/account/resources/identifiers/list"
target="_blank"
class="link link-primary"
>
Apple Developer Console
</a>
</li>
<li>{gettext("Create an App ID or select existing one")}</li>
<li>
{gettext("Enable")}
<strong>Sign in with Apple</strong> {gettext("capability")}
</li>
<li>
{gettext("Create a")}
<strong>Services ID</strong> {gettext("for web authentication")}
</li>
<li>
{gettext("Configure")}
<strong>Sign in with Apple</strong> {gettext("for the Services ID")}
</li>
<li>
{gettext("Add callback URL above to")} <strong>Return URLs</strong>
</li>
<li>
{gettext("Create a")} <strong>Private Key</strong>
{gettext("with Sign in with Apple enabled")}
</li>
<li>
{gettext("Copy")} <strong>Team ID</strong>, <strong>Key ID</strong>,
<strong>Client ID</strong>
({gettext("Services ID")}), {gettext("and")}
<strong>Private Key</strong>
{gettext("to fields above")}
</li>
<li>
{gettext("Click")}
<strong>Test Credentials</strong> {gettext("to verify setup")}
</li>
</ol>
</div>
<%!-- Reverse Proxy Notice --%>
<div class="bg-base-200 border border-base-300 rounded-lg p-3 text-xs">
<div class="flex items-start gap-2">
<.icon
name="hero-information-circle"
class="h-4 w-4 text-info shrink-0 mt-0.5"
/>
<div class="text-base-content/80">
<strong class="text-base-content">
{gettext("Reverse Proxy Users:")}
</strong>
{gettext("If behind nginx/apache, ensure")}
<code class="px-1 py-0.5 bg-base-300 text-base-content rounded text-xs">
X-Forwarded-Proto
</code>
{gettext("header is set to")}
<code class="px-1 py-0.5 bg-base-300 text-base-content rounded text-xs">
https
</code>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
<%!-- GitHub OAuth Credentials --%>
<div class={[
"card bg-base-200 p-4 mt-3",
if(@settings["oauth_github_enabled"] != "true", do: "hidden", else: "")
]}>
<h3 class="font-semibold mb-3 flex items-center gap-2">
<PhoenixKitWeb.Components.Core.Icons.icon_github class="h-5 w-5" />
{gettext("GitHub OAuth Credentials")}
</h3>
<div class="grid grid-cols-1 md:grid-cols-2 gap-3">
<div class="form-control">
<label class="label">
<span class="label-text">{gettext("Client ID")}</span>
</label>
<input
type="text"
name="settings[oauth_github_client_id]"
value={@settings["oauth_github_client_id"] || ""}
placeholder={gettext("Your GitHub OAuth Client ID")}
class="input input-bordered"
/>
</div>
<div class="form-control">
<label class="label">
<span class="label-text">{gettext("Client Secret")}</span>
</label>
<input
type="password"
name="settings[oauth_github_client_secret]"
value={@settings["oauth_github_client_secret"] || ""}
placeholder={gettext("Your GitHub OAuth Client Secret")}
class="input input-bordered"
/>
</div>
</div>
<button
type="button"
phx-click="test_oauth"
phx-value-provider="github"
class="btn btn-sm btn-outline mt-3 w-fit"
>
{gettext("Test Credentials")}
</button>
<%!-- GitHub OAuth Setup Instructions --%>
<div class="collapse collapse-arrow bg-base-200 mt-4">
<input type="checkbox" class="peer" />
<div class="collapse-title text-sm font-medium">
{gettext("Setup Instructions")}
</div>
<div class="collapse-content text-sm space-y-4">
<%!-- Callback URL Section --%>
<div class="bg-base-100 border border-base-300 rounded-lg p-4">
<div class="flex items-start gap-3">
<.icon
name="hero-information-circle"
class="stroke-current shrink-0 h-5 w-5 text-info mt-0.5"
/>
<div class="flex-1 min-w-0">
<div class="text-sm font-semibold text-base-content mb-2">
{gettext("Callback URL")}
</div>
<div class="flex items-center gap-2">
<code class="flex-1 px-3 py-2 bg-base-200 text-base-content border border-base-300 rounded font-mono text-xs break-all">
{get_oauth_callback_url(@settings, "github")}
</code>
<button
type="button"
class="btn btn-sm btn-square btn-outline"
onclick={"navigator.clipboard.writeText('#{get_oauth_callback_url(@settings, "github")}')"}
title={gettext("Copy to clipboard")}
>
<.icon name="hero-clipboard" class="h-4 w-4" />
</button>
</div>
<div class="text-xs text-base-content/60 mt-2">
{gettext("Copy this URL to GitHub OAuth Apps")}
</div>
</div>
</div>
</div>
<%!-- Step-by-step Instructions --%>
<div class="space-y-3">
<ol class="list-decimal list-inside space-y-2 text-base-content/80">
<li>
{gettext("Visit")}
<a
href="https://github.com/settings/developers"
target="_blank"
class="link link-primary"
>
GitHub Developer Settings
</a>
</li>
<li>
{gettext("Go to")} <strong>OAuth Apps</strong>
<strong>New OAuth App</strong>
</li>
<li>
{gettext("Enter")} <strong>Application name</strong>
{gettext("and")} <strong>Homepage URL</strong>
</li>
<li>
{gettext("Add callback URL above to")}
<strong>Authorization callback URL</strong>
</li>
<li>
{gettext("Click")} <strong>Register application</strong>
</li>
<li>
{gettext("Copy")} <strong>Client ID</strong>
{gettext("and generate/copy")} <strong>Client Secret</strong>
</li>
<li>
{gettext("Click")}
<strong>Test Credentials</strong> {gettext("to verify setup")}
</li>
</ol>
</div>
<%!-- Reverse Proxy Notice --%>
<div class="bg-base-200 border border-base-300 rounded-lg p-3 text-xs">
<div class="flex items-start gap-2">
<.icon
name="hero-information-circle"
class="h-4 w-4 text-info shrink-0 mt-0.5"
/>
<div class="text-base-content/80">
<strong class="text-base-content">
{gettext("Reverse Proxy Users:")}
</strong>
{gettext("If behind nginx/apache, ensure")}
<code class="px-1 py-0.5 bg-base-300 text-base-content rounded text-xs">
X-Forwarded-Proto
</code>
{gettext("header is set to")}
<code class="px-1 py-0.5 bg-base-300 text-base-content rounded text-xs">
https
</code>
</div>
</div>
</div>
</div>
</div>
</div>
<%!-- Facebook OAuth Credentials --%>
<div class={[
"card bg-base-200 p-4 mt-3",
if(@settings["oauth_facebook_enabled"] != "true", do: "hidden", else: "")
]}>
<h3 class="font-semibold mb-3 flex items-center gap-2">
<PhoenixKitWeb.Components.Core.Icons.icon_facebook class="h-5 w-5" />
{gettext("Facebook OAuth Credentials")}
</h3>
<div class="grid grid-cols-1 md:grid-cols-2 gap-3">
<div class="form-control">
<label class="label">
<span class="label-text">{gettext("App ID")}</span>
</label>
<input
type="text"
name="settings[oauth_facebook_app_id]"
value={@settings["oauth_facebook_app_id"] || ""}
placeholder={gettext("Your Facebook App ID")}
class="input input-bordered"
/>
</div>
<div class="form-control">
<label class="label">
<span class="label-text">{gettext("App Secret")}</span>
</label>
<input
type="password"
name="settings[oauth_facebook_app_secret]"
value={@settings["oauth_facebook_app_secret"] || ""}
placeholder={gettext("Your Facebook App Secret")}
class="input input-bordered"
/>
</div>
</div>
<button
type="button"
phx-click="test_oauth"
phx-value-provider="facebook"
class="btn btn-sm btn-outline mt-3 w-fit"
>
{gettext("Test Credentials")}
</button>
<%!-- Facebook OAuth Setup Instructions --%>
<div class="collapse collapse-arrow bg-base-200 mt-4">
<input type="checkbox" class="peer" />
<div class="collapse-title text-sm font-medium">
{gettext("Setup Instructions")}
</div>
<div class="collapse-content text-sm space-y-4">
<%!-- Callback URL Section --%>
<div class="bg-base-100 border border-base-300 rounded-lg p-4">
<div class="flex items-start gap-3">
<.icon
name="hero-information-circle"
class="stroke-current shrink-0 h-5 w-5 text-info mt-0.5"
/>
<div class="flex-1 min-w-0">
<div class="text-sm font-semibold text-base-content mb-2">
{gettext("Callback URL")}
</div>
<div class="flex items-center gap-2">
<code class="flex-1 px-3 py-2 bg-base-200 text-base-content border border-base-300 rounded font-mono text-xs break-all">
{get_oauth_callback_url(@settings, "facebook")}
</code>
<button
type="button"
class="btn btn-sm btn-square btn-outline"
onclick={"navigator.clipboard.writeText('#{get_oauth_callback_url(@settings, "facebook")}')"}
title={gettext("Copy to clipboard")}
>
<.icon name="hero-clipboard" class="h-4 w-4" />
</button>
</div>
<div class="text-xs text-base-content/60 mt-2">
{gettext("Copy this URL to Facebook App Settings")}
</div>
</div>
</div>
</div>
<%!-- Step-by-step Instructions --%>
<div class="space-y-3">
<ol class="list-decimal list-inside space-y-2 text-base-content/80">
<li>
{gettext("Visit")}
<a
href="https://developers.facebook.com/apps"
target="_blank"
class="link link-primary"
>
Facebook Developers Console
</a>
</li>
<li>
{gettext("Create a new app or select existing one")}
</li>
<li>
{gettext("Add")} <strong>Facebook Login</strong> {gettext("product")}
</li>
<li>
{gettext("Go to")} <strong>Facebook Login</strong>
<strong>Settings</strong>
</li>
<li>
{gettext("Add callback URL above to")}
<strong>Valid OAuth Redirect URIs</strong>
</li>
<li>
{gettext("Go to")} <strong>Settings</strong><strong>Basic</strong>
</li>
<li>
{gettext("Copy")} <strong>App ID</strong>
{gettext("and")} <strong>App Secret</strong>
{gettext("to fields above")}
</li>
<li>
{gettext("Switch app from")} <strong>Development</strong>
{gettext("to")} <strong>Live</strong>
{gettext("mode")}
</li>
<li>
{gettext("Click")}
<strong>Test Credentials</strong> {gettext("to verify setup")}
</li>
</ol>
</div>
<%!-- Reverse Proxy Notice --%>
<div class="bg-base-200 border border-base-300 rounded-lg p-3 text-xs">
<div class="flex items-start gap-2">
<.icon
name="hero-information-circle"
class="h-4 w-4 text-info shrink-0 mt-0.5"
/>
<div class="text-base-content/80">
<strong class="text-base-content">
{gettext("Reverse Proxy Users:")}
</strong>
{gettext("If behind nginx/apache, ensure")}
<code class="px-1 py-0.5 bg-base-300 text-base-content rounded text-xs">
X-Forwarded-Proto
</code>
{gettext("header is set to")}
<code class="px-1 py-0.5 bg-base-300 text-base-content rounded text-xs">
https
</code>
</div>
</div>
</div>
</div>
</div>
</div>
<%!-- OAuth Configuration Notice --%>
<div class="alert alert-info text-sm mt-3 max-w-prose">
<.icon name="hero-information-circle" class="stroke-current shrink-0 h-5 w-5" />
<div>
<div class="font-semibold">{gettext("OAuth Setup Instructions")}</div>
<div class="text-xs">
<p>{gettext("1. Enable the provider above and save settings")}</p>
<p>{gettext("2. Enter your OAuth credentials in the form that appears")}</p>
<p>{gettext("3. Save settings again to store credentials")}</p>
<p>{gettext("4. Click \"Test Credentials\" to verify configuration")}</p>
<p class="mt-1">
{gettext(
"Note: OAuth providers require ueberauth dependencies to be installed."
)}
</p>
</div>
</div>
</div>
<%!-- Reload OAuth Configuration Button --%>
<button
type="button"
phx-click="reload_oauth_config"
class="btn btn-sm btn-outline btn-secondary mt-3"
>
<PhoenixKitWeb.Components.Core.Icons.icon_refresh class="h-4 w-4" />
{gettext("Reload OAuth Configuration")}
</button>
<% end %>
</div>
<%!-- Action Buttons --%>
<div class="flex gap-3 pt-4">
<button
type="submit"
class={[
"btn btn-primary flex-1",
if(@saving, do: "loading", else: "")
]}
disabled={@saving}
>
<%= if @saving do %>
{gettext("Saving...")}
<% else %>
{gettext("Save Authorization Settings")}
<% end %>
</button>
</div>
</.form>
</div>
</div>
</div>
<.live_component
:if={@show_media_selector}
module={PhoenixKitWeb.Live.Components.MediaSelectorModal}
id="authorization-media-selector"
show={@show_media_selector}
mode={:single}
selected_uuids={[]}
phoenix_kit_current_user={assigns[:phoenix_kit_current_user]}
/>
</PhoenixKitWeb.Components.LayoutWrapper.app_layout>