Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Errors: Handle Auth Failure Conditions #16

Open
5 tasks
nelsonic opened this issue Nov 29, 2019 · 1 comment
Open
5 tasks

Errors: Handle Auth Failure Conditions #16

nelsonic opened this issue Nov 29, 2019 · 1 comment
Assignees
Labels
chore enhancement New feature or request help wanted Extra attention is needed priority-2 T1d technical

Comments

@nelsonic
Copy link
Member

nelsonic commented Nov 29, 2019

As a person using the @dwyl app to be more personally effective,
I do not want to stumble at the first hurdle trying to authenticate.
I don't expect to see unfriendly/unrecoverable error messages,
rather I expect to be able to recover from errors without drama.

At present our get_token/1 function is only following the "happy path":

def get_token(code) do
body = Poison.encode!(
%{ client_id: Application.get_env(:elixir_auth_google, :google_client_id),
client_secret: Application.get_env(:elixir_auth_google, :google_client_secret),
redirect_uri: Application.get_env(:elixir_auth_google, :google_redirect_uri),
grant_type: "authorization_code",
code: code
})
@httpoison.post(@google_token_url, body)
|> parse_body_response()
end

The callback function is parse_body_response/1 which does not handle the {:error, err}

defp parse_body_response({:ok, response}) do
body = Map.get(response, :body)
if body == nil do
{:error, :no_body}
else
Poison.decode(body)
end
end

This is fine during MVP because as early "dogfooding" users we are tolerant of the failure/errors.
But as soon as we ship and show the MVP to (friendly) alpha test users, we need to have this done.

Todo:

  • Research and document the various failure conditions and HTTP status codes
  • Add failure case statement to handle all the error conditions.
  • Update the template to ensure that error conditions are displayed in a friendly way.
  • Update instructions in README.md > How? section to inform people about error scenarios.
  • Re-publish the hex.pm package with the error handling.

We do not need to handle the failures before we ship our MVP, let's come back to this when it's needed.

@nelsonic nelsonic changed the title Handle Auth Failure Conditions Errors: Handle Auth Failure Conditions Nov 29, 2019
@nelsonic nelsonic added the help wanted Extra attention is needed label Oct 8, 2021
@ndrean
Copy link
Contributor

ndrean commented Oct 26, 2022

All errors are 400;401 and 404 depending on the bad input.
You can consider this possible solution:

def parse_response({:error, response}), do: {:error, response}
def parse_response({:ok, response}), do: get_user_profile(response.access_token)

def parse_status({:ok, %{status_code: 200}} = response), do:  parse_body_response(response)
def parse_status({:ok, _}), do: {:error, :bad_input}

# or more verbose

def parse_status(request) do
    case request do
      {:ok, %{status_code: 200} = response} ->
        parse_body_response({:ok, response})
 
      {:ok, %{status_code: 404}} ->
        {:error, :wrong_url}

      {:ok, %{status_code: 401}} ->
        {:error, :unauthorized_with_bad_secret}

      {:ok, %{status_code: 400}} ->
        {:error, :bad_code}
    end
 end

and use it: (get_token refactored to get_profile to expose only one function)

def get_profile(code, conn) do
    Jason.encode!(%{
      client_id: google_client_id(),
      client_secret: google_client_secret(),
      redirect_uri: generate_redirect_uri(conn),
      grant_type: "authorization_code",
      code: code
    })
    |> then(fn body ->
      inject_poison().post(@google_token_url, body)
      |> parse_status()
      |> parse_response()
    end)
 end

defp get_user_profile(access_token) do
    access_token
    |> encode()
    |>then(fn params ->
      (@google_user_profile <> "?" <> params)
      |> inject_poison().get()
      |> parse_status()
    end)
end

defp encode(token), do: URI.encode_query(%{access_token: token}, :rfc3986)
defp parse_body_response({:error, err}), do: {:error, err}
defp parse_body_response({:ok, %{body: nil}}), do: {:error, :no_body}

defp parse_body_response({:ok, %{body: body}}) do
    {:ok,
     body
     |> Jason.decode!()
     |> convert()}
end

defp convert(str_key_map) do
    for {key, val} <- str_key_map, into: %{}, do: {String.to_atom(key), val}
end

@nelsonic nelsonic moved this to 📋 Backlog in dwyl app kanban Nov 11, 2022
@nelsonic nelsonic moved this from 📋 Backlog to 🔖 Ready for Development in dwyl app kanban May 24, 2023
@nelsonic nelsonic moved this from 🔖 Ready for Development to 📋 Backlog in dwyl app kanban May 24, 2023
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
chore enhancement New feature or request help wanted Extra attention is needed priority-2 T1d technical
Projects
Status: 📋 Backlog
Development

No branches or pull requests

3 participants