9

I have django social-auth installed (from omab) and the users have an email address in database that is the one I want to keep but when the users log in from facebook using social-auth, their email gets replaced by the one they have in their facebook account. I am not sure the settings are the one by default or not and cannot find how to stop this behavior.

Bastian
  • 5,625
  • 10
  • 44
  • 68

3 Answers3

9

Have you tried SOCIAL_AUTH_PROTECTED_USER_FIELDS? :)

From the manual:

The update_user_details pipeline processor will set certain fields on user objects, such as email. Set this to a list of fields you only want to set for newly created users:

SOCIAL_AUTH_PROTECTED_USER_FIELDS = ['email',]

Also more extra values will be stored if defined. Details about this setting are listed below in the OpenId and OAuth sections.

Community
  • 1
  • 1
Zhe Li
  • 1,103
  • 1
  • 14
  • 20
  • today I would definitely do that, but back in the days that was another story :) Protected fields was not introduced yet. – Bastian Apr 29 '13 at 10:40
  • Yeah, I know. I was trying to solve it yesterday and I almost went for glarrain's solution. Then I found this settings in the manual. Just put it here in case someone TL;DR the manual:) – Zhe Li Apr 29 '13 at 11:22
5

I found it, in the pipeline the responsible for that is

social_auth.backends.pipeline.user.update_user_details

I just removed it from the pipeline and now the details like email address and name are left to the user to fill.

istruble
  • 13,363
  • 2
  • 47
  • 52
Bastian
  • 5,625
  • 10
  • 44
  • 68
3

I'm posting my solution (update user details, not overwrite them) so it may help someone. Based on pipeline.user.update_user_details I coded the following:

def fill_user_details(backend, details, response, user, is_new=False, *args,
                        **kwargs):
    """Fills user details using data from provider, without overwriting
    existing values.

    backend: Current social authentication backend
    details: User details given by authentication provider
    response: ?
    user: User ID given by authentication provider
    is_new: flag

    source: social_auth.backends.pipeline.user.update_user_details
    """
    # Each pipeline entry must return a dict or None, any value in the dict
    # will be used in the kwargs argument for the next pipeline entry.
    #
    # If any function returns something else beside a dict or None, the
    # workflow will be cut and the value returned immediately, this is useful
    # to return HttpReponse instances like HttpResponseRedirect.

    changed = False  # flag to track changes

    for name, value in details.iteritems():
        # do not update username, it was already generated
        if name in (USERNAME, 'id', 'pk'):
            continue

        # set it only if the existing value is not set or is an empty string
        existing_value = getattr(user, name, None)
        if value is not None and (existing_value is None or
                                  not is_valid_string(existing_value)):
            setattr(user, name, value)
            changed = True

    # Fire a pre-update signal sending current backend instance,
    # user instance (created or retrieved from database), service
    # response and processed details.
    #
    # Also fire socialauth_registered signal for newly registered
    # users.
    #
    # Signal handlers must return True or False to signal instance
    # changes. Send method returns a list of tuples with receiver
    # and it's response.
    signal_response = lambda (receiver, response): response
    signal_kwargs = {'sender': backend.__class__, 'user': user,
                     'response': response, 'details': details}

    changed |= any(filter(signal_response, pre_update.send(**signal_kwargs)))

    # Fire socialauth_registered signal on new user registration
    if is_new:
        changed |= any(filter(signal_response,
            socialauth_registered.send(**signal_kwargs)))

    if changed:
        user.save()
glarrain
  • 8,031
  • 7
  • 31
  • 44
  • Hi. How exactly do I go about implementing the solution you've posted above in my Django application? Where exactly should the above piece of code go? – Arpit Rai Apr 04 '13 at 15:07
  • @ArpitRai If you have a relatively new version of `social-auth` I recommed you use Zhe's answer (http://stackoverflow.com/a/16267281/556413) – glarrain Apr 21 '14 at 21:51