Search code examples
djangodjango-modelsdjango-viewsdjango-formsdjango-templates

django-allauth: redirect on log-in to sign-up page if social account exists


I want to create a Google Login authentication method in my Django project. So, when a user visits my website for the first time, it will create a new user in my database and then login that user. In case a user with this email address already exists, that user will simply log in.

The first part of my goal works as expected (when a user visits my website for the first time, it will create a new user in my database and then login that user), but If I'm trying to log in as an existing user, django-allauth redirects me to /accounts/social/signup/

enter image description here

I've tried to fix it with a CustomSocialAccountAdapter, but it didn't really help me. Could you help me please to resolve my problem?

Here is my settings.py :

# allauth
AUTHENTICATION_BACKENDS = [
    "django.contrib.auth.backends.ModelBackend",
    "allauth.account.auth_backends.AuthenticationBackend",
]

SOCIALACCOUNT_PROVIDERS = {
    "google": {
        "APP": {
            "client_id": os.environ.get("GOOGLE_CLIENT_ID", ""),
            "secret": os.environ.get("GOOGLE_CLIENT_SECRET", ""),
        },
        "SCOPE": [
            "profile",
            "email",
        ],
        "AUTH_PARAMS": {
            "access_type": "offline",
        },
    },
}
ACCOUNT_LOGIN_REDIRECT_URL = "home"
ACCOUNT_LOGOUT_REDIRECT_URL = "home"
SOCIALACCOUNT_LOGIN_ON_GET = True
SOCIALACCOUNT_LOGOUT_ON_GET = True
ACCOUNT_AUTHENTICATION_METHOD = "email"
ACCOUNT_EMAIL_REQUIRED = True
ACCOUNT_USERNAME_REQUIRED = False
ACCOUNT_UNIQUE_EMAIL = True
ACCOUNT_USER_MODEL_USERNAME_FIELD = None
SOCIALACCOUNT_AUTO_SIGNUP = True
ACCOUNT_LOGOUT_ON_GET = True
SOCIALACCOUNT_ADAPTER = "user.adapters.CustomSocialAccountAdapter"

My adapters.py :

class CustomSocialAccountAdapter(DefaultSocialAccountAdapter):
    def pre_social_login(self, request, sociallogin):
        user = sociallogin.user
        if not CustomUser.objects.filter(email=user.email).exists():
            extra_data = sociallogin.account.extra_data
            user.first_name = extra_data.get('given_name')
            user.last_name = extra_data.get('family_name')
            user.is_active = True
            user.save()

        else:
            perform_login(request, user, 'none')

        return super().pre_social_login(request, sociallogin)

My HTML code:

<a
  class="login-social__link"
  href="{% provider_login_url 'google' process='login' method='oauth2'>
  <svg class="login__icon login-google">
  <use
      xlink:href="{% static 'images/sprite-icons.svg' %}#icon-google"
  ></use>
  </svg>
</a>

Solution

  • I just modified adapters.py like so:

        from allauth.account.models import EmailAddress
    
        def pre_social_login(self, request, sociallogin):
            try:
                user = CustomUser.objects.get(email=sociallogin.user.email)
                sociallogin.connect(request, user)
                email_address, created = EmailAddress.objects.get_or_create(user=user, email=user.email)
                
                if not email_address.verified:
                    email_address.verified = True
                    email_address.primary = True
                    email_address.save()
                ...
    
            except CustomUser.DoesNotExist:
                ...
    

    When a user tries to login via a social account and that social account's email matches an email already in the database, django-allauth attempts to link the social account to the existing user account. If it cannot do so automatically (for instance, due to missing or mismatched data), it redirects to the signup page as a fallback.