PowEmailConfirmation.Plug.email_unconfirmed?/1 always returning false

Hello, I’ve been trying to implement Pow in my phoneix project. So far everything was working fine, till I tried to deny authorization to unconfirmed emails.

The code for confirming email is as follows:

def show(conn, %{"id" => token}) do
    case PowEmailConfirmation.Plug.load_user_by_token(conn, token) do
      {:error, conn} ->
        conn
        |> put_status(401)
        |> json(%{error: %{status: 401, message: "Invalid confirmation code"}})

      {:ok, conn} ->
        case PowEmailConfirmation.Plug.confirm_email(conn, %{}) do
          {:ok, _, conn} ->
            conn
            |> json(%{success: %{message: "Email confirmed"}})

          {:error, _, conn} ->
            conn
            |> put_status(401)
            |> json(%{error: %{status: 401, message: "Invalid confirmation code"}})
        end
    end
  end

The email confirmation is working fine as it can be seen from the following:

  #Dakpeon.Users.User<
    __meta__: #Ecto.Schema.Metadata<:loaded, "users">,
    address: nil,
    company_name: nil,
    completion_status: false,
    email: "test1@example.com",
    email_confirmation_token: nil,
    email_confirmed_at: ~U[2021-12-20 15:25:29Z],
    first_name: nil,
    id: 5,
    inserted_at: ~N[2021-12-20 15:23:43],
    last_name: nil,
    role: "user",
    unconfirmed_email: nil,
    updated_at: ~N[2021-12-20 15:25:29],
    wallet: #Ecto.Association.NotLoaded<association :wallet is not loaded>,
    ...
  >

But the problem is whenever I call PowEmailConfirmation.Plug.email_unconfirmed?/1 I always get false. For now, I was just trying to see the output of Plug.email_unconfirmed?/1 because my logic didn’t work and that confused me.

  def create(conn, %{"user" => user_params}) do
    conn
    |> PowEmailConfirmation.Plug.email_unconfirmed?()
    |> IO.inspect()

    conn
    |> Pow.Plug.authenticate_user(user_params)
    |> case do
      {:ok, conn} ->
        json(conn, %{data: %{access_token: conn.private.api_access_token, renewal_token: conn.private.api_renewal_token}})

      {:error, conn} ->
        conn
        |> put_status(401)
        |> json(%{error: %{status: 401, message: "Invalid email or password"}})
    end
  end

Following is the output of a test user.

[debug] Processing with DakpeonWeb.API.V1.SessionController.create/2
  Parameters: %{"user" => %{"email" => "test3@example.com", "password" => "[FILTERED]"}}
  Pipelines: [:api]
false
[debug] QUERY OK source="users" db=3.6ms idle=1476.6ms
SELECT u0."id", u0."first_name", u0."last_name", u0."address", u0."company_name", u0."role", u0."completion_status", u0."unconfirmed_email", u0."email_confirmed_at", u0."email_confirmation_token", u0."password_hash", u0."email", u0."inserted_at", u0."updated_at" FROM "users" AS u0 WHERE (u0."email" = $1) ["test3@example.com"]

The user details:

  #Dakpeon.Users.User<
    __meta__: #Ecto.Schema.Metadata<:loaded, "users">,
    address: nil,
    company_name: nil,
    completion_status: false,
    email: "test3@example.com",
    email_confirmation_token: "a31b635c-90b2-4cd7-b702-8f16afcf3b60",
    email_confirmed_at: nil,
    first_name: nil,
    id: 7,
    inserted_at: ~N[2021-12-27 08:53:56],
    last_name: nil,
    role: "user",
    unconfirmed_email: nil,
    updated_at: ~N[2021-12-27 08:53:56],
    wallet: #Ecto.Association.NotLoaded<association :wallet is not loaded>,
    ...
  >

This calling the email_unconfirmed?/1 function on this data should return true, according to the source code.

also, another user whose email is confirmed: (not including the user struct, cause it’s been provided before in this post)

[debug] Processing with DakpeonWeb.API.V1.SessionController.create/2
  Parameters: %{"user" => %{"email" => "test1@example.com", "password" => "[FILTERED]"}}
  Pipelines: [:api]
false
[debug] QUERY OK source="users" db=2.2ms idle=1713.9ms
SELECT u0."id", u0."first_name", u0."last_name", u0."address", u0."company_name", u0."role", u0."completion_status", u0."unconfirmed_email", u0."email_confirmed_at", u0."email_confirmation_token", u0."password_hash", u0."email", u0."inserted_at", u0."updated_at" FROM "users" AS u0 WHERE (u0."email" = $1) ["test1@example.com"]
[info] Sent 200 in 971ms

I’m completely lost. why it’s always returning false, is beyond my understanding. Any suggestion will be helpful!

Thanks!

PowEmailConfirmation.Plug.email_unconfirmed? gets the current user from the conn, but that isn’t set until Pow.Plug.authenticate_user runs.

1 Like

ah, thanks a lot! :+1: