Open pelmenept opened 4 years ago
Thanks!
- 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.
Can you help me understand the exact state the user is in here? They were invited, clicked the link, update with password, and then they try to sign in with google after?
And is failed to insert into users table due to constraint
the exact error message, if not can you post the one, and possibly stacktrace?
It sounds like the issue experienced in https://github.com/pow-auth/pow_assent/issues/113 and I'm thinking of resolving like https://github.com/pow-auth/pow_assent/issues/115.
For sure.
The state of the user:
It used to just error out on Repo.Insert into users, but now it handles error (Not sure if it is due to recent update)
08:32:30.650 request_id=Ff0XYTdaIOfbOe8AAAyB [debug] QUERY OK db=0.1ms idle=8470.1ms
begin []
%Plug.Conn{
08:32:30.653 request_id=Ff0XYTdaIOfbOe8AAAyB [debug] QUERY ERROR db=2.9ms
INSERT INTO "users" ("email","email_confirmed_at","first_name","last_name","role","thumbnail","inserted_at","updated_at") VALUES ($1,$2,$3,$4,$5,$6,$7,$8) RETURNING "id" ["myemail@gmail.com", ~U[2020-03-17 12:32:30Z], "first_name", "last_name", "user", "https://lh3.googleusercontent.com/a-/Arandom_keyw", ~U[2020-03-17 12:32:30Z], ~U[2020-03-17 12:32:30Z]]
08:32:30.654 request_id=Ff0XYTdaIOfbOe8AAAyB [debug] QUERY OK db=0.1ms
rollback []
It seems to rollback transaction now on error.
Basically social login will always fail if user already exists in database in "users" table but has no identity assigned in "user_identities"
thank you
Edit: It looks like a similar issue to the ones you referenced, but I am not 100% sure. What I am struggling to understand, is that authentication through google works fine if user already exists in "users" table (was invited) AND query string contains "invitation token". Then POW does not try to insert user, but only inserts user_identity, and works correctly. So how do I turn authentication through similar flow on regular logins, when user exists in "users" but identity is not yet setup?
It's because when the user follows the invite link, the struct is already loaded in the conn, so it's in an "authenticated" state and the identity will be upserted. The same happens when a user is authenticated and then links a provider. When there's no user in the conn the logic will instead attempt to create identity and user at the same time.
This is the same as discussed in the linked issues.
So a constraint error will occur and the user is redirected to set the e-mail manually. I think permitted verified provider emails to automatically link up with the user could work, but really #115 is the best solution. Ideally you have to authenticate with an existing method for your account before you can add a new auth method. I hope I can open a PR to do this very soon.
If you want to do something similar to the above, then I would recommend that you create a custom controller overriding the :add_user_id
logic. You could load the provider params or changeset stored in the session, and then attempt to load the user based on the email in either of those.
Thank you very much for your help.
@danschultzer As this issue is open, I will add another scenario here that I came across related to social auth.
I'm using both pow & pow_assent for api only authentication.
I have set user_id_field: :username on my user schema.
First I created a user using username say 'akash' along with email/password which worked just fine.
The issue comes when I'm trying to register another account with oauth (discord in this case).
The discord account returns the same username akash
when registering with discord (has different email than first user).
This throws a unique constraint error (users_username_index) as a user with akash
as username already exists.
How can I handle such cases? (I think probability of this occuring is high with discord as discord allows having same username for multiple users and differentiate with username#12123, but returns only the part before # in oauth callback flow).
I'm not sure how to handle it within my user model, would always doing a update_change on username field to add random string (and allow the user to change username later ) in the assent changeset (user_identity_changset) be a good idea?
How can I handle such cases? (I think probability of this occuring is high with discord as discord allows having same username for multiple users and differentiate with username#12123, but returns only the part before # in oauth callback flow).
I'm not sure how to handle it within my user model, would always doing a update_change on username field to add random string (and allow the user to change username later ) in the assent changeset (user_identity_changset) be a good idea?
Yeah, this would be the easiest solution!
It's not great though, what would be better UX would be that the user corrects the username themselves. This goes together with the refactor I want to do with #195 #170 and this one, to allow for more dynamic handling of changeset errors. Ideally any errors that the end-user can fix should be displayed to them, and anything apart from that should result in redirect error.
Thanks, my current implementation is to add a random string with # prefix and complete the upsert as I did not see any way to take additional input from user with the api and keep the oauth flow going. I am adding additional logic on frontend to redirect user to change username if it is marked to change.
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:
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:
As long as users use the same method to login, the way they logged in first, there are no problems.
After some digging, the flow for authentication or upsert is done in PowAssent.Plug:
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:
Thank you very much, please let me know if I am wrong somewhere.