omab / python-social-auth

Social auth made simple
http://psa.matiasaguirre.net
BSD 3-Clause "New" or "Revised" License
2.83k stars 1.09k forks source link

Slack oauth authentication issues #954

Closed asieira closed 7 years ago

asieira commented 8 years ago

I'm running into a problem using the Slack OAuth2 authentication.

Firstly, the documentation at http://psa.matiasaguirre.net/docs/backends/slack.html says that "also it’s possible to define extra permissions with" SOCIAL_AUTH_SLACK_SCOPE. This implies providing this variable is optional.

However, if I don't set this variable or if I set it to an empty list, Slack gives me the following error: OAuth Error: blank_scope: Requested scopes cannot be blank.

If I set SOCIAL_AUTH_SLACK_SCOPE to ['identify'], the authentication does work and a user is created. However, the user is completely devoid or any details, with an empty name, e-mail, etc to the point where this causes errors in Django admin. I'm guessing this is because no user details were obtained due to the lack of scopes identity.basic, identity.email, as per https://api.slack.com/docs/sign-in-with-slack.

But I set the value to include additional options, such as ['identify','identity.email'] or any other identity. values whatsoever alongside identify, I also get the following error from Slack: OAuth Error: invalid_scope: Cannot request both identity scopes and other scopes at the same time.

Really having trouble getting this to work, need some help (and believe the documentation needs some serious revisions).

asieira commented 8 years ago

Ok, I was finally able to make this work by setting SOCIAL_AUTH_SLACK_SCOPE to ['identity.basic'], however the first name, last name and e-mail address are not being set on the Django user even if I add identity.email. Any ideas on what might be going on?

asieira commented 8 years ago

Ok, after much investigation I was able to determine that the default implementation of Slack OAuth was not correctly getting the user details since it was trying to use the users.info operation instead of the users.identity one which is recommended in the Sign In with Slack documentation. In my environment the former does not work (users never get names or e-mails populated) while the latter does.

So I implemented a subclass that works for me and allows me to properly obtain the user name and e-mail. Plus, it allows authentication to be restricted to a configurable list of Slack teams, since in my case this was a needed feature:

from social.backends.slack import SlackOAuth2
from social.exceptions import AuthFailed

class FixedSlackOAuth2(SlackOAuth2):
    DEFAULT_SCOPE = ['identity.basic','identity.email']

    def get_user_details(self, response):
        retval = {}

        if 'name' in response['user']:
            retval['fullname'] = response['user']['name']
            s = retval['fullname'].split()
            retval['first_name'] = s[0]
            if len(s) > 1:
                retval['last_name'] = ' '.join(s[1:])

        if 'email' in response['user']:
            retval['email'] = response['user']['email']

        retval['username'] = '{0}:{1}@slack'.format(response['user']['id'], response['team']['id'])

        return retval

    def user_data(self, access_token, *args, **kwargs):
        user_identity = self.get_json('https://slack.com/api/users.identity', params={'token': access_token})
        user_identity['id'] = user_identity['user']['id']
        if not user_identity.get('ok', False):
            raise AuthFailed(self.name, user_identity.get('error', 'users.identity operation failed'))
        return user_identity

    def auth_allowed(self, response, details):
        """Return True if the user should be allowed to authenticate, by
        default check if email is whitelisted (if there's a whitelist)"""
        teams = self.setting('ALLOWED_TEAMS', [])
        if not teams:
            return True
        elif 'team' in response and 'id' in response['team']:
            return response['team']['id'] in teams
        else:
            return False
omab commented 7 years ago

I've updated the Slack backend in the social-core module.