How to implement Authentication with Multiple OAuth2 Providers?

I have have already implemented email/password auth and now I want to add OAuth2 login with multiple providers (Google and Facebook). I saw the guide for Google, but not sure how to set up multiple providers together.
6 Replies
ZachDaniel
ZachDaniel3mo ago
the DSLs can just sit alongside eachother
oauth :foo do

end

oauth :bar do

end

google do

end
oauth :foo do

end

oauth :bar do

end

google do

end
Joan Gavelán
Joan GavelánOP3mo ago
Oh yeah, now I understood the purpose of these configs. Zach, I have previously used Assent so I rolled my own multiprovider module and controller. Is it completely fine if I use Ash only for the upsert action?
create :register_with_oauth2 do
argument :user_info, :map, allow_nil?: false
argument :oauth_tokens, :map, allow_nil?: false

upsert? true
upsert_identity :unique_email
upsert_fields []

change AshAuthentication.GenerateTokenChange

change fn changeset, _ ->
user_info = Ash.Changeset.get_argument(changeset, :user_info)

changes = %{
"email" => user_info["email"],
"first_name" => user_info["given_name"],
"last_name" => user_info["family_name"],
"picture" => user_info["picture"]
}

Ash.Changeset.change_attributes(changeset, changes)
end

change set_attribute(:confirmed_at, &DateTime.utc_now/0)
end
create :register_with_oauth2 do
argument :user_info, :map, allow_nil?: false
argument :oauth_tokens, :map, allow_nil?: false

upsert? true
upsert_identity :unique_email
upsert_fields []

change AshAuthentication.GenerateTokenChange

change fn changeset, _ ->
user_info = Ash.Changeset.get_argument(changeset, :user_info)

changes = %{
"email" => user_info["email"],
"first_name" => user_info["given_name"],
"last_name" => user_info["family_name"],
"picture" => user_info["picture"]
}

Ash.Changeset.change_attributes(changeset, changes)
end

change set_attribute(:confirmed_at, &DateTime.utc_now/0)
end
I also don't think I need the identity_resource config as I'm supporting basic auth based on email upserts. What do you think, is there something I should be aware of?
ZachDaniel
ZachDaniel3mo ago
Yep, 100% as in its totally fine to do that 🙂 You can do whatever you want to do at the end of the day all Ash cares about is getting an actor set for its action calls So AshAuthentication does a bunch of cool stuff but if it doesn't fit it is actually a pretty clean separation in general.
Joan Gavelán
Joan GavelánOP3mo ago
Awesome. Thank you for the great support Zach. Highly appreciated. I ran into a small issue in the final step, it seems that the change AshAuthentication.GenerateTokenChange cannot generate the token if there is no oauth configuration in my User module (however I am doing this with Assent on my own module as pointed out above) I'm getting this error when triggering my :register_with_oauth2 action:
Ash.Error.Unknown at GET /auth/google/callback
Bread Crumbs:
> Exception raised in: Culturalismo.Accounts.User.register_with_oauth2

Unknown Error

* ** (MatchError) no match of right hand side value: :error
(ash_authentication 4.9.6) lib/ash_authentication/generate_token_change.ex:16: anonymous fn/4 in AshAuthentication.GenerateTokenChange.change/3
Ash.Error.Unknown at GET /auth/google/callback
Bread Crumbs:
> Exception raised in: Culturalismo.Accounts.User.register_with_oauth2

Unknown Error

* ** (MatchError) no match of right hand side value: :error
(ash_authentication 4.9.6) lib/ash_authentication/generate_token_change.ex:16: anonymous fn/4 in AshAuthentication.GenerateTokenChange.change/3
ZachDaniel
ZachDaniel3mo ago
Hm...you can configure the oauth strategy with some dummy values, or go open up the changes source and make your own change to generate a token.
Joan Gavelán
Joan GavelánOP3mo ago
Yeah, simply configuring the oauth2 block with dummy/empty values worked
oauth2 :oauth2 do
client_id ""
client_secret ""
redirect_uri ""
base_url ""
authorize_url ""
token_url ""
user_url ""
end
oauth2 :oauth2 do
client_id ""
client_secret ""
redirect_uri ""
base_url ""
authorize_url ""
token_url ""
user_url ""
end
Thanks

Did you find this page helpful?