achedeuzot / ueberauth_auth0

Auth0 OAuth2 strategy for Überauth.
https://hexdocs.pm/ueberauth_auth0
MIT License
71 stars 46 forks source link

KeyError: key :body not found in: %OAuth2.Error{reason: :timeout} #193

Closed benkimpel closed 9 months ago

benkimpel commented 2 years ago

Hello @achedeuzot,

On rare occasions I've gotten this error: KeyError: key :body not found in: %OAuth2.Error{reason: :timeout}

Here's the stack trace

KeyError: key :body not found in: %OAuth2.Error{reason: :timeout}
  File "lib/ueberauth/strategy/auth0.ex", line 154, in Ueberauth.Strategy.Auth0.handle_callback!/1
  File "lib/ueberauth/strategy.ex", line 364, in Ueberauth.Strategy.run_handle_callback/2
  File "lib/my_app_web/controllers/auth_controller.ex", line 1, in MyAppWeb.AuthController.phoenix_controller_pipeline/2
    defmodule MyAppWeb.AuthController do
  File "lib/phoenix/router.ex", line 355, in Phoenix.Router.__call__/2
  File "lib/my_app_web/endpoint.ex", line 1, in MyAppWeb.Endpoint.plug_builder_call/2
    defmodule MyAppWeb.Endpoint do
  File "lib/my_app_web/endpoint.ex", line 1, in MyAppWeb.Endpoint."call (overridable 3)"/2
    defmodule MyAppWeb.Endpoint do
  File "lib/my_app_web/endpoint.ex", line 1, in MyAppWeb.Endpoint.call/2
    defmodule MyAppWeb.Endpoint do
  File "lib/phoenix/endpoint/cowboy2_handler.ex", line 43, in Phoenix.Endpoint.Cowboy2Handler.init/4

It looks like the code here /lib/ueberauth/strategy/auth0.ex#L154 is expecting an %OAuth2.Response{}, but in this case it's getting an %OAuth2.Error{} which only has a :reason key.

achedeuzot commented 2 years ago

Indeed, it looks like you're having timeouts.

The function called is handle_callback!/1 (notice the bang) so when something fails, it will raise an error which is expected. Still, if you see a better way of surfacing the error, feel free to submit a PR or I'll look into it in the upcoming weeks.

benkimpel commented 2 years ago

Thanks for the quick response! I'd be happy to do a PR.

In this case my approach would be to pattern match and send it to set_errors! separately. That will let it get passed through to the user's controller as an ueberauth failure.

#/lib/ueberauth/strategy/auth0.ex

case result do
  {:ok, client} ->
    token = client.token

    if token.access_token == nil do
      set_errors!(conn, [
        error(
          token.other_params["error"],
          token.other_params["error_description"]
        )
      ])
    else
      fetch_user(conn, client, state)
    end

  # Added ↓
  {:error, %OAuth2.Error{reason: reason}} ->
    set_errors!(conn, [error("OAuth2 error", reason)])
  # Added ↑

  {:error, client} ->
    set_errors!(conn, [error(client.body["error"], client.body["error_description"])])
end

If that approach seems reasonable to you I'll open up a PR soon.

achedeuzot commented 2 years ago

This approach looks good :) Happy to see a PR with this improvement !