Protocol Enumerable not implemented for error with guardian login

First time trying Guardian–I did not know that!

Seems like you’ve confused one with the other because of

alias Dog.{UserManager, UserManager.User, UserManager.Guardian}

And, I checked that line to make sure that Guardian.Plug was indeed equivalent to Dog.UserManager.Guardian.Plug! All that code is from the official Guardian “Getting Started Tutorial”.

And, the route problem I was having was due to the tutorial alternately using “/protected” and “/secret” to refer to the Guardian protected route.

By the way, things work when I do:

 alias Dog.{UserManager, UserManager.User, UserManager.Guardian}
 ...
 new_conn = Guardian.Plug.sign_in(conn, user)

So, I guess I was looking at the wrong docs??? This is what my lib/dog/user_manager/guardian.ex file looks like:

defmodule Dog.UserManager.Guardian do
  use Guardian, otp_app: :dog
  alias Dog.UserManager

  def subject_for_token(user, _claims) do
    # You can use any value for the subject of your token but
    # it should be useful in retrieving the resource later, see
    # how it being used on `resource_from_claims/1` function.
    # A unique `id` is a good subject, a non-unique email address
    # is a poor subject.

    {:ok, to_string(user.id)}
  end

  def resource_from_claims(%{"sub" => id}) do
    # Here we'll look up our resource from the claims, the subject can be
    # found in the `"sub"` key. In `above subject_for_token/2` we returned
    # the resource id so here we'll rely on that to look it up.

    case UserManager.get_user(id) do
      nil -> {:error, :user_not_found}
      user -> {:ok, user}
    end
  end

end

I guess the line:

use Guardian, otp_app: :dog

injects a Plug module? I looked at the source code for the Guardian module:

 defmacro __using__(opts \\ []) do
    otp_app = Keyword.get(opts, :otp_app)

    # credo:disable-for-next-line Credo.Check.Refactor.LongQuoteBlocks
    quote do
      @behaviour Guardian

      if Code.ensure_loaded?(Plug) do
        __MODULE__
        |> Module.concat(:Plug)    
        |> Module.create(  ## CREATES THE Dog.UserManager.Guardian.Plug MODULE
          quote do
            use Guardian.Plug, unquote(__MODULE__)
          end,
          Macro.Env.location(__ENV__)
        )
      end

And Guardian.Plug’s __using__() function looks like this:

   defmacro __using__(impl) do
      quote do
        ...
        ...
        def sign_in(conn, resource, claims \\ %{}, opts \\ []),
          do: Guardian.Plug.sign_in(conn, implementation(), resource, claims, opts)

And, there’s the two argument sign_in() function that I lucked into; and, like you said, the way I was calling it originally:

Guardian.Plug.sign_in(conn, Guaridan, user)

matched the parameter variable claims to user.

lol. And the original solution to this question was:

ok found something, I changed it into this:
|> Guardian.Plug.sign_in(user)

Thanks idiot!

2 Likes