6
votes

I've used Devise as a standard authentication gem for other projects. In another project, I've used Devise + Omniauth for Twitter authentication.

In a new project I need my end users to be able to login via Twitter and Facebook or to be able to register via the app. In the future the user could link his accounts together. For example, his Twitter and Facebook account. Or, his Twitter and "native" account. "Native" being the account he registered with directly with the web app.

Is Devise capable of such? If so, how do we link the accounts of users together? What is the concept behind this? How does the app know which Facebook and Twitter account belong to which user?

Ideas and suggestions welcome.

EDIT:

I've been following http://railscasts.com/episodes/236-omniauth-part-2?autoplay=true and what i dont get is. If

  1. user is signed out of app,
  2. user has an account registered with app,
  3. user signs in with a different service provider (facebook, twitter, etc).

How does the app know how to link his new service provider with his already existing accounts?

Stackoverflow.com has this feature. But one service provider they are not including in their "multi-sign" on feature is Twitter. I'm guessing it's because Twitter doesn't expose the user's email through their API. While the other service providers (Facebook, Yahoo, Gmail) does.

4

4 Answers

3
votes

Email is generally used to link all the accounts, but with Twitter, you can't get the email account. Using the email is not really a good practice, because the user did not necessarily register to each service with the same email address.

Asking the user if he wants to use facebook/twitter/google/openid for authentication once he's logged in is the easiest way, and the more predictable for the user. You must prevent the effect "how does this website know my facebook account? Why are they tracking me?"

As a side note, the hardest part is not adding a new authentication method, but merging the accounts if the user, as an example, created one account with facebook, and one with twitter.

1
votes

Devise is perfectly capable of that, but since every provider has its own token you need a way to recognize the user no matter with which provider he chosen to log in.

The most common way to do it is by using the email field, you need to ask for the email in each provider request, I personally don't like it because users can still have different emails in different providers.

To overcome this you can provide a option "connect my Facebook login with my Twitter login".

1
votes

Please look for this screencasts, it will help you: OmniAuth

and OmniAuth part2

Recently I'he played with such problem as you have now. I goal was to implement many authentication solutions: Google, Twitter, Facebook .. at the same time - so user can login with multiple providers(like in Stackoverflow.com) and after logout he stay logged in with another service. I have implemented this by creating next schema (I have no my code right now but it should give you a clue):

class User
 has_many :authentications
 has_many :known_authentications
end

class Authentication
  #implemented nearly as in Ryan's Railscasts (It keeps authorization info)
end

class KnownAuthentications
  #has :provider, :user_id, :uid and :email columns. Here I keep all authorizations for registered user, that he ever had(so I can verify user by email and guess that this is the same user as logged in from different services). I fill this table when user registers with any service(Google, Twitter etc.). 
end

When User logges in I check KnownAuthentifications table for current authorization service by email (OpenID service pass email with other parameters, OAuth - don't (so here I create fake email, say [email protected] -> so Devise do not throughs exceptin)). Know I now that user logged in from Google is the same as currently logged in from Twitter.

0
votes

I have this same question and although this isn't a complete solution (I don't think one really is 100% foolproof) this is what I'm building now.

Example: A site with username/password, Facebook, and Twitter for authentication.

A user comes to the site and wants to register. They register using Twitter for authentication. Twitter passes a bunch of information except email address. I am storing profile information (location, name, etc) that I think will be useful for comparison. The user is presented with a profile page immediately after authentication to verify profile information (they can remove any information they don't want stored). They also have the chance to add additional authentication methods (in this case, username/password and Facebook). The more you encourage them to link additional authentication methods while logged in the less trouble you will have with duplicated accounts. However it still exists as an edge case.

The edge case scenario goes like this: the user signs up with Twitter then immediately signs out and tries to sign in using Facebook. The sign in method detects that this is a new authentication and so it compares the oauth data from Facebook with existing profile information and tries to find matches. I then display the top 10 or so matches and ask the user to verify if they already exist so the account can be linked. Have the user sign in using Twitter and then link the Facebook account.

Obviously this would be easier and simpler if everyone used the same email address and Twitter would actually return an email address. But not everyone does so you have to handle this edge case in the best way you can - at this point I'll try the matching option and just push users to authenticate with other services as they sign up and fill in profile information.