djangodjango-1.5django-allauth

Django allauth social login: automatically linking social site profiles using the registered email


I aim to create the easiest login experience possible for the users of my Django site. I imagine something like:

  1. Login screen is presented to user
  2. User selects to login with Facebook or Google
  3. User enter password in external site
  4. User can interact with my site as an authenticated user

Ok, this part is easy, just have to install django-allauth and configure it.

But I also want to give the option to use the site with a local user. It would have another step:

  1. Login screen is presented to user
  2. User selects to register
  3. User enter credentials
  4. Site sends a verification email
  5. User clicks in email link and can interact with my site as an authenticated user

Ok, both the default authentication and allauth can do it. But now is the million dollars question.

If they change how they do the login, how do I automatically associate their Google, FB and local accounts?

See that any way they login, I have their email address. Is it possible to do it using django-allauth? I know I can do it with user intervention. Today the default behavior is to refuse the login saying that the email is already registered.

If it isn't possible to do just with configuration, I'll accept the answer that gives me some orientation about which modifications should I make in allauth code to support this workflow.

There are a lot of reasons to do this. The users will forget which method they used to authenticate, and will sometimes use Google, sometimes FB and sometimes the local user account. We already have a lot of local user accounts and social accounts will be a new feature. I want the users to maintain their identity. I envision the possibility to ask for the user friends list, so if they logged using Google, I'd like to also have their FB account.

It is a hobby site, there isn't great security requirements, so please don't answer that this isn't a wise security implementation.

Later, I'd create a custom user model to have just the email as the login id. But I'll be happy with an answer that just let me automatically associate a accounts of the default user model that has a required username.

I'm using Django==1.5.4 and django-allauth==0.13.0


Solution

  • You will need to override the sociallogin adapter, specifically, the pre_social_login method, which is called after authentication with the social provider, but before this login is processed by allauth.

    In my_adapter.py, do something like this

    from django.contrib.auth.models import User
    
    from allauth.account.models import EmailAccount
    from allauth.exceptions import ImmediateHttpResponse
    from allauth.socialaccount.adapter import DefaultSocialAccountAdapter
    
    
    class MyAdapter(DefaultSocialAccountAdapter):
        def pre_social_login(self, request, sociallogin):
            # This isn't tested, but should work
            try:
                user = User.objects.get(email=sociallogin.email)
                sociallogin.connect(request, user)
                # Create a response object
                raise ImmediateHttpResponse(response)
            except User.DoesNotExist:
                pass
    

    And in your settings, change the social adapter to your adapter

    SOCIALACCOUNT_ADAPTER = 'myapp.my_adapter.MyAdapter`
    

    And you should be able to connect multiple social accounts to one user this way.