[Django]-Django-social-auth create new user programmatically by facebook_id

3šŸ‘

āœ…

Use this custom backend that sets the username to the personā€™s FACEBOOK_ID.

from social_auth.backends.facebook import FacebookBackend
class IDFacebookBackend(FacebookBackend):
    """Facebook OAuth2 authentication backend"""
    def get_user_details(self, response):
        """Return user details from Facebook account"""
        return {'username': response.get('id'),
                'email': response.get('email', ''),
                'fullname': response.get('name', ''),
                'first_name': response.get('first_name', ''),
                'last_name': response.get('last_name', '')}

Use this version of get_username in your auth pipleline instead of social_auth.backends.pipeline.user.get_username

def get_username(details, user=None, *args, **kwargs):
    " Make Username from User Id "
    if user:
        return {'username': UserSocialAuth.user_username(user)}
    else:
        return details['username']

Your pipeline should look like this:

SOCIAL_AUTH_PIPELINE = (
    'social_auth.backends.pipeline.social.social_auth_user',
    'our_custom_auth.get_username', # <= This should be the previous function
    'social_auth.backends.pipeline.user.create_user',
    'social_auth.backends.pipeline.social.associate_user',
    'social_auth.backends.pipeline.social.load_extra_data',
    'social_auth.backends.pipeline.user.update_user_details'
)

Then all you need to do is call User.objects.create(username=friends_facebook_id) and you have a User that cannot login with username/pass, but can be referenced easily through ForeignKey fields.

Also, when that ā€œFriendā€ comes and joins up with your site at a later date (Using SocialAuth), they will automatically be given this User object and your internal graph will stay accurate.

šŸ‘¤Thomas

0šŸ‘

So I used the idea described above but with less effort and eventually I ended up with the following:

I overrode associate_by_email stage from SOCIAL_AUTH_PIPELINE to my own implementation of associate_by_username. Since username is unique in Django auth we can use that.
So totally changes are

  1. Implement associate_by_username

    from django.core.exceptions import MultipleObjectsReturned, ObjectDoesNotExist
    from social_auth.exceptions import AuthException
    from django.contrib.auth.models import User

    def associate_by_username(details, user=None, *args, **kwargs):
    ā€œā€ā€Return user entry with same email address as one returned on details.ā€ā€ā€
    if user:
    return None

    username = details.get('username')
    
    if username:
        try:
            return {'user': User.objects.get(username=username)}
        except MultipleObjectsReturned:
            raise AuthException(kwargs['backend'], 'Not unique email address.')
        except ObjectDoesNotExist:
            pass
    
  2. Then I add this method to pipeline

    SOCIAL_AUTH_PIPELINE = (
    ā€˜social_auth.backends.pipeline.social.social_auth_userā€™,
    ā€˜core.auth.associate_by_usernameā€™,
    ā€˜social_auth.backends.pipeline.user.get_usernameā€™,
    ā€˜social_auth.backends.pipeline.user.create_userā€™,
    ā€˜social_auth.backends.pipeline.social.associate_userā€™,
    ā€˜social_auth.backends.pipeline.social.load_extra_dataā€™,
    ā€˜social_auth.backends.pipeline.user.update_user_detailsā€™,
    )

  3. And when I need to get user I look it up by facebookId (recipient = UserSocialAuth.objects.filter(uid=target_facebook_id)
    ) but create by facebookUsername (User(username=target_username))

šŸ‘¤zjor

Leave a comment