-
-
Notifications
You must be signed in to change notification settings - Fork 52
Description
Hi! First thank you very much for the library, pretty much the only authentication for phoenix.
I am experiencing some difficulties with authentication flow using social providers when user already exists. Let me know if I am wrong, but pretty much steps to reproduce:
I have below extensions installed:
- PowInvitation
- PowEmailconfirmation
- PowAssent
In my app, users can invite other users. This flow seems to be working correctly. Once user invites another one, they receive email. Here is where it breaks for me:
User has 2 ways of continuing after confirming email:
- Enter password, and log in -> works perfectly fine
- Click on "sign in with google", get couple redirects, and get logged in -> works perfectly fine.
As long as users use the same method to login, the way they logged in first, there are no problems.
- If user confirmed email using google authentication, they are still able to "reset password" and then login. This user now can login using both google or password login methods.
- Hovewer user that has confirmed email and set up password, is not able to login using google authentication anymore. The error that I am getting with this approach "failed to insert into users table due to constraint". Which seems pow_assent is trying to insert user, and then insert user_identity, which does not work, since user already exists.
After some digging, the flow for authentication or upsert is done in PowAssent.Plug:
defp maybe_authenticate(
%{
private: %{
pow_assent_callback_state: {:ok, :strategy},
pow_assent_callback_params: params
}
} = conn
) do
user_identity_params = Map.fetch!(params, :user_identity)
case Pow.Plug.current_user(conn) do
nil ->
conn
|> authenticate(user_identity_params)
|> case do
{:ok, conn} -> conn
{:error, conn} -> conn
end
_user ->
conn
end
end
Up until maybe_authenticate call everything works correctly. But "authenticate" call only tries to pull user from user_identities and not from users. Thus user is not found and nil is returned. Since authentication failed, assent tries to insert user, but failes, since user exists in "users" table but not in "user_identities" table.
authenticate code:
@spec authenticate(Conn.t(), map()) :: {:ok, Conn.t()} | {:error, Conn.t()}
def authenticate(conn, %{"provider" => provider, "uid" => uid}) do
config = fetch_config(conn)
provider
|> Operations.get_user_by_provider_uid(uid, config)
|> case do
nil -> {:error, conn}
user -> {:ok, Plug.create(conn, user)}
end
end
Thank you very much, please let me know if I am wrong somewhere.