fix: adds user friendly flas message

This commit is contained in:
carla 2026-02-17 19:29:49 +01:00
parent 2b1f49d60a
commit a25263b721
7 changed files with 163 additions and 12 deletions

View file

@ -45,4 +45,11 @@ defmodule MvWeb.AuthOverrides do
Gettext.gettext(MvWeb.Gettext, "or")
end)
end
# Hide AshAuthentication's Flash component since we use flash_group in root layout
# This prevents duplicate flash messages
override AshAuthentication.Phoenix.Components.Flash do
set :message_class_info, "hidden"
set :message_class_error, "hidden"
end
end

View file

@ -33,6 +33,7 @@
</script>
</head>
<body>
<.flash_group flash={@flash} />
{@inner_content}
</body>
</html>

View file

@ -57,7 +57,9 @@ defmodule MvWeb.AuthController do
handle_authentication_failed(conn, caused_by)
_ ->
redirect_with_error(conn, gettext("Incorrect email or password"))
conn
|> put_flash(:error, gettext("Incorrect email or password"))
|> redirect(to: ~p"/sign-in")
end
end
@ -74,14 +76,39 @@ defmodule MvWeb.AuthController do
handle_oidc_email_collision(conn, errors)
_ ->
redirect_with_error(conn, gettext("Unable to authenticate with OIDC. Please try again."))
conn
|> put_flash(:error, gettext("Unable to authenticate with OIDC. Please try again."))
|> redirect(to: ~p"/sign-in")
end
end
# Handle Assent server unreachable errors (network/connectivity issues)
defp handle_rauthy_failure(conn, %Assent.ServerUnreachableError{} = err) do
# Use warning level: server unreachable is often transient, not a critical system error
Logger.warning("OIDC authentication server unreachable", safe_assent_meta(err))
conn
|> put_flash(:error, gettext("The authentication server is currently unavailable. Please try again later."))
|> redirect(to: ~p"/sign-in")
end
# Handle Assent invalid response errors (configuration or malformed responses)
defp handle_rauthy_failure(conn, %Assent.InvalidResponseError{} = err) do
# Use warning level: configuration errors are operational issues, not critical failures
Logger.warning("OIDC authentication invalid response", safe_assent_meta(err))
conn
|> put_flash(:error, gettext("Authentication configuration error. Please contact the administrator."))
|> redirect(to: ~p"/sign-in")
end
# Catch-all clause for any other error types
defp handle_rauthy_failure(conn, reason) do
Logger.warning("Unhandled Rauthy failure reason: #{inspect(reason)}")
redirect_with_error(conn, gettext("Unable to authenticate with OIDC. Please try again."))
conn
|> put_flash(:error, gettext("Unable to authenticate with OIDC. Please try again."))
|> redirect(to: ~p"/sign-in")
end
# Handle generic AuthenticationFailed errors
@ -93,14 +120,20 @@ defmodule MvWeb.AuthController do
You can confirm your account using the link we sent to you, or by resetting your password.
""")
redirect_with_error(conn, message)
conn
|> put_flash(:error, message)
|> redirect(to: ~p"/sign-in")
else
redirect_with_error(conn, gettext("Authentication failed. Please try again."))
conn
|> put_flash(:error, gettext("Authentication failed. Please try again."))
|> redirect(to: ~p"/sign-in")
end
end
defp handle_authentication_failed(conn, _other) do
redirect_with_error(conn, gettext("Authentication failed. Please try again."))
conn
|> put_flash(:error, gettext("Authentication failed. Please try again."))
|> redirect(to: ~p"/sign-in")
end
# Handle OIDC email collision - user needs to verify password to link accounts
@ -112,7 +145,10 @@ defmodule MvWeb.AuthController do
nil ->
# Check if it's a "different OIDC account" error or email uniqueness error
error_message = extract_meaningful_error_message(errors)
redirect_with_error(conn, error_message)
conn
|> put_flash(:error, error_message)
|> redirect(to: ~p"/sign-in")
end
end
@ -177,13 +213,46 @@ defmodule MvWeb.AuthController do
|> redirect(to: ~p"/auth/link-oidc-account")
end
# Generic error redirect helper
defp redirect_with_error(conn, message) do
conn
|> put_flash(:error, message)
|> redirect(to: ~p"/sign-in")
# Extract safe metadata from Assent errors for logging
# Never logs sensitive data: no tokens, secrets, or full request URLs
# Returns keyword list for Logger.warning/2
defp safe_assent_meta(%{request_url: url} = err) when is_binary(url) do
[
request_url: redact_url(url),
http_adapter: Map.get(err, :http_adapter)
]
|> Enum.filter(fn {_key, value} -> not is_nil(value) end)
end
defp safe_assent_meta(%{response: %{status_code: status_code}} = err) do
[
status_code: status_code,
http_adapter: Map.get(err, :http_adapter)
]
|> Enum.filter(fn {_key, value} -> not is_nil(value) end)
end
defp safe_assent_meta(err) do
# Only extract safe, simple fields
[
http_adapter: Map.get(err, :http_adapter)
]
|> Enum.filter(fn {_key, value} -> not is_nil(value) end)
end
# Redact URL to only show scheme and host, hiding path, query, and fragments
defp redact_url(url) when is_binary(url) do
case URI.parse(url) do
%URI{scheme: scheme, host: host} when not is_nil(scheme) and not is_nil(host) ->
"#{scheme}://#{host}"
_ ->
"[redacted]"
end
end
defp redact_url(_), do: "[redacted]"
def sign_out(conn, _params) do
return_to = get_session(conn, :return_to) || ~p"/"