Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

External Login Account vs. Native Login Account

I am brand new to Visual Studio 2012 and MVC 4, and I've been working with the SimpleMembershipProvider via the WebMatrix.WebData library.

I'd like to integrate Facebook as an external login source down the road, but it's not a requirement as of right now. However, to get a decent feel for what it would take, I've been following the tutorial and guide found here - http://www.asp.net/mvc/tutorials/mvc-4/using-oauth-providers-with-mvc.

My question :

If a user has already been created using :

WebSecurity.CreateUserAndAccount(model.Email, model.Password);
WebSecurity.Login(model.Email, model.Password);

Can they be "upgraded" to an oAuthMemebership account in the future, if they choose to use their Facebook credentials instead of the email and password they created when first signing up?

I couldn't find a clear answer to this question in the guide, or elsewhere, so I'm hoping someone can clarify how that process may work.

like image 686
X3074861X Avatar asked May 03 '13 19:05

X3074861X


1 Answers

The SimpleMembership setup allows for a local and multiple OAuth logins all sharing the same UserProfile - so a single user can login with either a local password, or FacebOogLiveWitter.

(I should state, that I'm assuming in this answer that the OAuth provider does not send back a matching piece of information for a local account. If they do then the principles of actually performing the merge are the same, but the complexity and steps are vastly reduced.)

The OAuth registration process will refuse the user if they use an existing user name, rather than try and merge two accounts. Therefore this isn't simple, you'll have to build the functionality yourself. The process is complex as there are many directions the user can approach this from (so you could simplify by only supporting one or two), and you need to enforce security as well in case someone tries to merge into an account they don't own.

I will assume you are comfortable with the link you've posted, and you've followed the Facebook help at (for example) Facebook Login and The Login Flow for Web (without JavaScript SDK) so you have a working test application.

Your general process has to have multiple user journey approaches to make sense to a user:

  1. for a logged in user (with a local account)
    1. let them login to facebook and associate the accounts
    2. let them merge an existing account on your site which uses a facebook login
  2. for a logged-in user (with a facebook account)
    1. let them create a local account
    2. let them merge an existing local account on your site
  3. for a non logged in user who tries to register a local account
    1. let them merge this new account with a facebook login that is already registered, and do that as part of the registration process
  4. for a non logged in user who tries to register (or log in for the first time with) a facebook account
    1. let them link this with an existing local account as part of the registration process

etc.

ASK PERMISSION

(You can skip this if the OAuth provider has sent back a matching identifying piece of information, such as an email address).

You should enforce confirmation security, usually through email confirmation sent to the target account of the merge. Otherwise:

  • someone can login to your site with facebook for the first time
  • during that process say they "own" the email address or username of a local account (remember, facebook won't necessarily confirm what their email is for you)
  • and therefore gain access to the existing local account

So, once the merge "request" is made, you need to ask for permission to proceed from the target account of the merge.

The MVC 4 AccountController

I will use Facebook as our OAuth example. To compare what happens when you register a user on your local authentication framework vs. OAuth:

  • Local: creates an entry in webpages_Membership and an entry with the same UserId in UserProfile (assuming you are using the default tables for the MVC 4 application template)
  • OAuth: creates an entry in webpages_OAuthMembership and an entry with the same UserId in UserProfile

Now let's look at what happens when a user signs in using Facebook for the first time:

  • They click on Login using Facebook (or whatever your button says)
  • they get taken to facebook to login
  • they succeed (let's assume that, and ignore the failure case)
  • they then get sent, invisibly to them, to /Account/ExternalLoginCallback
  • OAuthWebSecurity.SerializeProviderUserId is called, passing the OAuth details to that Action
  • They get redirected to /Account/ExternalLoginConfirmation and asked to provide a username for their new presence on your site
  • If that user name is available then UserProfile and webpages_OAuthMembership entries are created

This process is your chance to "join" the accounts by matching some unique piece of information. As long as you end up with the same UserId in UserProfile, webpages_Membership and webpages_OAuthMembership you should be ok. So we have to intercept the process at the point of /Account/ExternalLoginConfirmation.

If the OAuth provider has sent back a matching identifying piece of information, such as an email address, this becomes simple, test for this in the ExternalLoginConfirmation action, and auto-merge using a similar process to the one outlined below.

However, I think you can't/shouldn't assume that the user uses the same email address for your site and OAuth, (nor should you for many reasons). Also, probably in the T&Cs for something like FacebOogLiveWitter it stops you asking for the email of their account anyway, and if they don't currently they might in future.

So instead, you could link the accounts based on alternatives, like username or email address, or phone number. Either way you are going to need them to input some identifying piece of information that is unique against an account, and will pull back the target account.

Wrapping up

So to put this all together: In the first part of this answer I outlined how you will need to consider multiple user journeys to merge accounts. I will use the example 4.1.

Your process will need to:

(Assumption - when a user first registers with a local account, you ask them for an email address and validate it or assume it is valid)

  • Let the user login with facebook for the first time
  • at Account/ExternalLoginConfirmation ask them if they want to
    • Create a new account with you
    • Use their facebook login to access an existing account
  • Assuming the latter, then you log a request in a new table (maybe "MergeAccountRequests") with:
    • The facebook account UserId
    • The target merge local account UserId
    • An authorisation code to use in the email you need to send (From this point on, if they login without confirming that merge, they will have to get sent to a page to ask them to confirm, rather than create objects in other db tables which you have to worry about later)
  • You then send an email to the address of the target merge (local) account asking for permission to complete the merge (a standard confirmation email, with a link)
  • When they click on that link, or enter the code you sent them (you could use SMS as well as email) then you need to merge the two accounts
    • Choose the "new" and "target accounts (in this case "new" is the facebook account as you don't have data associated with it yet)
    • Delete the UserProfile of the "new" account
    • Change the UserId of the "new" account webpages_OAuthMembership table to the same as the "target" account
    • Log the user out (so there are no complications depending on which account they are currently logged in with)
    • Display a message to the user telling them the merge is almost complete and that they can now log in with either account to confirm and complete the merge

Rather than send them to a login page, i would give them the login options alongside the confirmation message.

like image 138
Andy Brown Avatar answered Oct 04 '22 07:10

Andy Brown