From f0f53d5a7a597afba7bf1329f1b5ca5fafc0554f Mon Sep 17 00:00:00 2001 From: Arno Dirlam Date: Wed, 23 Oct 2019 19:49:20 +0200 Subject: [PATCH] More descriptive error message on OAuth request_token failure (#31) * More descriptive error message on request failure * Request JSON responses from API, Decode JSON responses in HTTP function, Adjust error handling * Clean up and format affected functions --- lib/ueberauth/strategy/twitter.ex | 6 +++--- lib/ueberauth/strategy/twitter/internal.ex | 23 +++++++++++++++++++++- lib/ueberauth/strategy/twitter/oauth.ex | 21 +++++++++++++++++--- 3 files changed, 43 insertions(+), 7 deletions(-) diff --git a/lib/ueberauth/strategy/twitter.ex b/lib/ueberauth/strategy/twitter.ex index de6af23..52185f4 100644 --- a/lib/ueberauth/strategy/twitter.ex +++ b/lib/ueberauth/strategy/twitter.ex @@ -101,17 +101,17 @@ defmodule Ueberauth.Strategy.Twitter do defp fetch_user(conn, token) do params = [{"include_entities", false}, {"skip_status", true}, {"include_email", true}] + case Twitter.OAuth.get("/1.1/account/verify_credentials.json", params, token) do {:ok, %{status_code: 401, body: _, headers: _}} -> set_errors!(conn, [error("token", "unauthorized")]) - {:ok, %{status_code: status_code, body: body, headers: _}} when status_code in 200..399 -> - body = Ueberauth.json_library().decode!(body) + {:ok, %{status_code: status_code, body: body, headers: _}} when status_code in 200..399 -> conn |> put_private(:twitter_token, token) |> put_private(:twitter_user, body) + {:ok, %{status_code: _, body: body, headers: _}} -> - body = Ueberauth.json_library().decode!(body) error = List.first(body["errors"]) set_errors!(conn, [error("token", error["message"])]) end diff --git a/lib/ueberauth/strategy/twitter/internal.ex b/lib/ueberauth/strategy/twitter/internal.ex index 98d55ff..0d966b7 100644 --- a/lib/ueberauth/strategy/twitter/internal.ex +++ b/lib/ueberauth/strategy/twitter/internal.ex @@ -15,9 +15,30 @@ defmodule Ueberauth.Strategy.Twitter.OAuth.Internal do |> OAuther.sign(url, extraparams, creds) |> OAuther.header - HTTPoison.get(url, [header], params: params) + HTTPoison.get(url, [header, {"Accept", "application/json"}], params: params) + |> decode_body() end + def decode_body({:ok, response}) do + content_type = + Enum.find_value(response.headers, fn + {"content-type", val} -> val + _ -> nil + end) + + case content_type do + "application/json" <> _ -> + json_body = Ueberauth.json_library().decode!(response.body) + json_response = %{response | body: json_body} + {:ok, json_response} + + _ -> + {:ok, response} + end + end + + def decode_body(other), do: other + def params_decode(resp) do resp |> String.split("&", trim: true) diff --git a/lib/ueberauth/strategy/twitter/oauth.ex b/lib/ueberauth/strategy/twitter/oauth.ex index 5aa8629..7b3ae5b 100644 --- a/lib/ueberauth/strategy/twitter/oauth.ex +++ b/lib/ueberauth/strategy/twitter/oauth.ex @@ -17,6 +17,18 @@ defmodule Ueberauth.Strategy.Twitter.OAuth do request_token: "/oauth/request_token", site: "https://api.twitter.com"] + defmodule ApiError do + @moduledoc "Raised on OAuth API errors." + + defexception [:message, :code] + + def message(e = %{code: nil}), do: e.message + + def message(e) do + "#{e.message} (Code #{e.code})" + end + end + def access_token({token, token_secret}, verifier, opts \\ []) do opts |> client() @@ -73,19 +85,22 @@ defmodule Ueberauth.Strategy.Twitter.OAuth do defp consumer(client), do: {client.consumer_key, client.consumer_secret, :hmac_sha1} - defp decode_response({:ok, %{status_code: 200, body: body, headers: _}}) do + defp decode_response({:ok, %{status_code: 200, body: body}}) do params = Internal.params_decode(body) token = Internal.token(params) token_secret = Internal.token_secret(params) {:ok, {token, token_secret}} end - defp decode_response({:ok, %{status_code: status_code, body: _, headers: _}}) do - {:error, "#{status_code}"} + + defp decode_response({:ok, %{status_code: status_code, body: %{"errors" => [error | _]}}}) do + {:error, %ApiError{message: error["message"], code: error["code"]}} end + defp decode_response({:error, %{reason: reason}}) do {:error, "#{reason}"} end + defp decode_response(error) do {:error, error} end