Packages

phoenix_kit

1.6.12
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 users oauth.ex
Raw

lib/phoenix_kit_web/users/oauth.ex

if Code.ensure_loaded?(Ueberauth) do
defmodule PhoenixKitWeb.Users.OAuth do
@moduledoc """
OAuth authentication controller using Ueberauth.
This controller requires the following optional dependencies to be installed:
- ueberauth
- ueberauth_google (for Google Sign-In)
- ueberauth_apple (for Apple Sign-In)
If these dependencies are not installed, a fallback controller will be used instead.
"""
use PhoenixKitWeb, :controller
plug PhoenixKitWeb.Plugs.EnsureOAuthScheme
# Ensure OAuth config is loaded before Ueberauth plug runs
# This prevents MatchError if configuration is missing
plug PhoenixKitWeb.Plugs.EnsureOAuthConfig
plug Ueberauth
alias PhoenixKit.Config
alias PhoenixKit.Settings
alias PhoenixKit.Users.OAuth
alias PhoenixKit.Utils.IpAddress
alias PhoenixKit.Utils.Routes
alias PhoenixKitWeb.Users.Auth, as: UserAuth
require Logger
@doc """
Initiates OAuth authentication flow.
"""
def request(conn, %{"provider" => provider} = params) do
Logger.debug("PhoenixKit OAuth request for provider: #{provider}")
# Check if OAuth is enabled in settings
if oauth_enabled_in_settings?() do
# Check if OAuth is properly configured
case get_ueberauth_providers() do
[] ->
Logger.warning("PhoenixKit OAuth: No providers configured")
conn
|> put_flash(
:error,
"OAuth authentication is not configured. To enable OAuth, please add provider configuration to your config.exs file. See PhoenixKit documentation for details."
)
|> redirect(to: Routes.path("/users/log-in"))
providers when providers != [] ->
provider_names =
Enum.map(providers, fn {provider, _strategy} -> to_string(provider) end)
Logger.debug("PhoenixKit OAuth: Available providers: #{inspect(provider_names)}")
if provider in provider_names do
handle_oauth_request(conn, params)
else
Logger.warning(
"PhoenixKit OAuth: Provider '#{provider}' not in configured providers: #{inspect(provider_names)}"
)
conn
|> put_flash(
:error,
"Provider '#{provider}' is not configured. Available providers: #{Enum.join(provider_names, ", ")}"
)
|> redirect(to: Routes.path("/users/log-in"))
end
error ->
Logger.error("PhoenixKit OAuth: Configuration error: #{inspect(error)}")
conn
|> put_flash(:error, "OAuth configuration error. Please contact your administrator.")
|> redirect(to: Routes.path("/users/log-in"))
end
else
Logger.warning("PhoenixKit OAuth: OAuth is disabled in settings")
conn
|> put_flash(
:error,
"OAuth authentication is currently disabled. Please contact your administrator to enable it."
)
|> redirect(to: Routes.path("/users/log-in"))
end
end
defp handle_oauth_request(conn, params) do
conn =
if referral_code = params["referral_code"] do
put_session(conn, :oauth_referral_code, referral_code)
else
conn
end
conn =
if return_to = params["return_to"] do
put_session(conn, :oauth_return_to, return_to)
else
conn
end
# Check if Ueberauth plug has already sent a response (e.g., a redirect)
# If response was already sent by Ueberauth, halt() to stop further processing
if conn.state != :unset do
# Response already sent by Ueberauth (e.g., redirect to OAuth provider)
halt(conn)
else
# No response sent - Ueberauth couldn't process the request
# This can happen if provider configuration is missing or invalid
Logger.error(
"PhoenixKit OAuth: Ueberauth plugin did not process request for provider. Check if GOOGLE_CLIENT_ID and GOOGLE_CLIENT_SECRET environment variables are set correctly."
)
conn
|> put_flash(
:error,
"OAuth authentication unavailable. The provider credentials are not configured. Please contact your administrator or use another sign-in method."
)
|> redirect(to: Routes.path("/users/log-in"))
end
end
defp get_ueberauth_providers do
providers = Config.UeberAuth.get_providers()
# Normalize Map or List to list of {provider_atom, strategy} tuples
case providers do
p when is_map(p) -> Map.to_list(p)
p when is_list(p) -> p
end
end
defp oauth_enabled_in_settings? do
Settings.get_boolean_setting("oauth_enabled", false)
end
@doc """
Handles OAuth callback from provider.
"""
def callback(%{assigns: %{ueberauth_auth: auth}} = conn, _params) do
track_geolocation = Settings.get_boolean_setting("track_registration_geolocation", false)
ip_address = IpAddress.extract_from_conn(conn)
referral_code = get_session(conn, :oauth_referral_code)
return_to = get_session(conn, :oauth_return_to)
opts = [
track_geolocation: track_geolocation,
ip_address: ip_address,
referral_code: referral_code
]
case OAuth.handle_oauth_callback(auth, opts) do
{:ok, user} ->
Logger.info(
"PhoenixKit: User #{user.id} (#{user.email}) authenticated via OAuth (#{auth.provider})"
)
conn =
conn
|> delete_session(:oauth_referral_code)
|> delete_session(:oauth_return_to)
flash_message = "Successfully signed in with #{format_provider_name(auth.provider)}!"
conn
|> put_flash(:info, flash_message)
|> UserAuth.log_in_user(user, return_to: return_to)
{:error, %Ecto.Changeset{} = changeset} ->
errors = format_changeset_errors(changeset)
Logger.warning(
"PhoenixKit: OAuth authentication failed for #{auth.info.email}: #{inspect(errors)}"
)
conn
|> put_flash(:error, "Authentication failed: #{errors}")
|> redirect(to: Routes.path("/users/log-in"))
{:error, reason} ->
Logger.error("PhoenixKit: OAuth authentication error: #{inspect(reason)}")
conn
|> put_flash(
:error,
"Authentication failed. Please try again or use a different sign-in method."
)
|> redirect(to: Routes.path("/users/log-in"))
end
end
def callback(%{assigns: %{ueberauth_failure: failure}} = conn, _params) do
error_message = format_ueberauth_failure(failure)
Logger.warning("PhoenixKit: OAuth authentication failure: #{inspect(failure)}")
conn
|> put_flash(:error, error_message)
|> redirect(to: Routes.path("/users/log-in"))
end
def callback(conn, _params) do
Logger.error("PhoenixKit: Unexpected OAuth callback without auth or failure")
conn
|> put_flash(:error, "Authentication failed. Please try again.")
|> redirect(to: Routes.path("/users/log-in"))
end
# Private helper functions
defp format_provider_name(provider) when is_atom(provider) do
provider |> to_string() |> format_provider_name()
end
defp format_provider_name("google"), do: "Google"
defp format_provider_name("apple"), do: "Apple"
defp format_provider_name("github"), do: "GitHub"
defp format_provider_name("facebook"), do: "Facebook"
defp format_provider_name("twitter"), do: "Twitter"
defp format_provider_name("microsoft"), do: "Microsoft"
defp format_provider_name(provider), do: String.capitalize(provider)
defp format_changeset_errors(changeset) do
Ecto.Changeset.traverse_errors(changeset, fn {msg, opts} ->
Enum.reduce(opts, msg, fn {key, value}, acc ->
String.replace(acc, "%{#{key}}", to_string(value))
end)
end)
|> Enum.map_join("; ", fn {field, errors} ->
"#{field}: #{Enum.join(errors, ", ")}"
end)
end
defp format_ueberauth_failure(%Ueberauth.Failure{errors: errors}) do
case errors do
[] ->
"Authentication failed. Please try again."
[%{message: message} | _] when is_binary(message) ->
"Authentication failed: #{message}"
_ ->
"Authentication failed. Please try again."
end
end
end
else
# Fallback controller when Ueberauth is not loaded
defmodule PhoenixKitWeb.Users.OAuth do
@moduledoc """
Fallback OAuth controller when Ueberauth dependencies are not installed.
This controller provides user-friendly error messages when OAuth authentication
is attempted but the required dependencies are not installed.
To enable OAuth authentication, add the following dependencies to your mix.exs:
{:ueberauth, "~> 0.10"},
{:ueberauth_google, "~> 0.12"}, # For Google Sign-In
{:ueberauth_apple, "~> 0.1"} # For Apple Sign-In
Then configure the providers in your config.exs as described in the PhoenixKit documentation.
"""
use PhoenixKitWeb, :controller
alias PhoenixKit.Utils.Routes
require Logger
@doc """
Handles OAuth request when Ueberauth is not available.
"""
def request(conn, %{"provider" => provider}) do
Logger.warning(
"PhoenixKit OAuth: Attempted to use #{provider} authentication but Ueberauth dependencies are not installed"
)
conn
|> put_flash(
:error,
"OAuth authentication is not available. Please install the required dependencies (ueberauth, ueberauth_#{provider}) and configure your application. See PhoenixKit documentation for details."
)
|> redirect(to: Routes.path("/users/log-in"))
end
@doc """
Handles OAuth callback when Ueberauth is not available.
"""
def callback(conn, _params) do
Logger.error(
"PhoenixKit OAuth: Received OAuth callback but Ueberauth dependencies are not installed"
)
conn
|> put_flash(
:error,
"OAuth authentication is not configured. Please contact your administrator."
)
|> redirect(to: Routes.path("/users/log-in"))
end
end
end