Skip to content

Commit ee2a27f

Browse files
authored
Improve authentication error handling for package fetching (#1116)
Warn instead of raising when OAuth authentication fails or is declined during dependency resolution since the user may only need public packages. Improve the prompt message when re-authentication is needed. Add 401 to the recognized error statuses in the registry server and suggest running `mix hex.user auth` when no authentication token is found.
1 parent 6fa6b0a commit ee2a27f

File tree

3 files changed

+27
-18
lines changed

3 files changed

+27
-18
lines changed

lib/hex/oauth.ex

Lines changed: 8 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -57,32 +57,28 @@ defmodule Hex.OAuth do
5757
store_token(new_token_data)
5858
{:ok, new_token_data["access_token"]}
5959

60-
{:error, :refresh_failed} = error ->
60+
{:error, :refresh_failed} ->
6161
if Keyword.get(opts, :prompt_auth, false) do
62-
prompt_and_authenticate("Token refresh failed. Please re-authenticate.")
62+
reauthenticate("Token refresh failed. Re-authenticating...")
6363
else
64-
error
64+
{:error, :refresh_failed}
6565
end
6666

67-
{:error, :no_refresh_token} = error ->
67+
{:error, :no_refresh_token} ->
6868
if Keyword.get(opts, :prompt_auth, false) do
69-
prompt_and_authenticate(
70-
"Access token expired and could not be refreshed. Please re-authenticate."
71-
)
69+
reauthenticate("Access token expired and could not be refreshed. Re-authenticating...")
7270
else
73-
error
71+
{:error, :no_refresh_token}
7472
end
7573
end
7674
end
7775

78-
defp prompt_and_authenticate(message) do
76+
defp reauthenticate(message) do
7977
Hex.Shell.info(message)
8078

81-
if Hex.Shell.yes?("No authenticated user found. Do you want to authenticate now?") do
79+
if Hex.Shell.yes?("Do you want to authenticate now?") do
8280
case Mix.Tasks.Hex.auth() do
8381
{:ok, token_data} ->
84-
# Store the new token (auth() already did this, but be explicit)
85-
# Return the access token
8682
{:ok, token_data["access_token"]}
8783

8884
:error ->

lib/hex/registry/server.ex

Lines changed: 11 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -409,14 +409,18 @@ defmodule Hex.Registry.Server do
409409
"Failed to fetch record for #{Hex.Utils.package_name(repo, package)} from registry#{cached_message}"
410410
)
411411

412-
if missing_status?(result) do
412+
if missing_or_unauthorized_status?(result) do
413413
Hex.Shell.error(
414414
"This could be because the package does not exist, it was spelled " <>
415415
"incorrectly or you don't have permissions to it"
416416
)
417+
418+
if unauthorized_status?(result) and not Hex.OAuth.has_tokens?() do
419+
Hex.Shell.error("No authenticated user found. Run `mix hex.user auth` to authenticate")
420+
end
417421
end
418422

419-
if not missing_status?(result) or Mix.debug?() do
423+
if not missing_or_unauthorized_status?(result) or Mix.debug?() do
420424
case result do
421425
{:error, :bad_signature} ->
422426
Hex.Shell.error(
@@ -442,8 +446,11 @@ defmodule Hex.Registry.Server do
442446
end
443447
end
444448

445-
defp missing_status?({:ok, {status, _, _}}), do: status in [403, 404]
446-
defp missing_status?(_), do: false
449+
defp missing_or_unauthorized_status?({:ok, {status, _, _}}), do: status in [401, 403, 404]
450+
defp missing_or_unauthorized_status?(_), do: false
451+
452+
defp unauthorized_status?({:ok, {status, _, _}}), do: status in [401, 403]
453+
defp unauthorized_status?(_), do: false
447454

448455
defp public_key_message("hexpm:" <> _), do: "on our public keys page: #{@public_keys_html}"
449456
defp public_key_message("hexpm"), do: "on our public keys page: #{@public_keys_html}"

lib/hex/remote_converger.ex

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -740,10 +740,16 @@ defmodule Hex.RemoteConverger do
740740
:ok
741741

742742
{:error, :auth_failed} ->
743-
Mix.raise("Authentication failed. Unable to access private packages.")
743+
Hex.Shell.warn(
744+
"Authentication failed. Private packages will not be available. " <>
745+
"Run `mix hex.user auth` to authenticate."
746+
)
744747

745748
{:error, :auth_declined} ->
746-
Mix.raise("Authentication required to access private packages. Run `mix hex.user auth`")
749+
Hex.Shell.warn(
750+
"Private packages will not be available. " <>
751+
"Run `mix hex.user auth` to authenticate."
752+
)
747753

748754
{:error, :no_auth} ->
749755
# No OAuth token - this is OK, user might only be fetching public packages

0 commit comments

Comments
 (0)