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!