0

Some time ago I've successfully integrated Superset authentication with Oauth using AWS Cognito.

Now I'm trying to do the same with Auth0, reusing the previous configuration and changing the endpoints according to Auth0 documentation.

Unfortunately, the login fails and Superset's log returns the following message:

2021-10-20 10:30:48,886:ERROR:flask_appbuilder.security.views:Error on OAuth authorize: request() got an unexpected keyword argument 'scope'

This is the Oauth configuration in superset_config.py:

from superset.security import SupersetSecurityManager

import json
import logging

logger = logging.getLogger(__name__)

class CustomSsoSecurityManager(SupersetSecurityManager):
    def oauth_user_info(self, provider, response=None):
        if provider == 'auth0':
            res = self.appbuilder.sm.oauth_remotes[provider].get('userinfo')
            if res.raw.status != 200:
                logger.error('Failed to obtain user info: %s', res.data)
                return
            me = json.loads(res._content)
            logger.warning(" user_data: %s", me)
            prefix = 'Superset'
            logging.warning("user_data: {0}".format(me))
            return {
                'username' : me['email'],
                'name' : me['name'],
                'email' : me['email'],
                'first_name': me['given_name'],
                'last_name': me['family_name'],
            }

AUTH_TYPE = AUTH_OAUTH
AUTH_USER_REGISTRATION = True
AUTH_USER_REGISTRATION_ROLE = "Public"

AUTH0_URL = os.getenv('AUTH0_URL')
AUTH0_CLIENT_KEY = os.getenv('AUTH0_CLIENT_KEY')
AUTH0_CLIENT_SECRET = os.getenv('AUTH0_CLIENT_SECRET')

OAUTH_PROVIDERS = [{
    'name':'auth0',
    'token_key': 'access_token',
    'icon':'fa-at',
    'url': AUTH0_URL,
    'remote_app': {
        'client_id': AUTH0_CLIENT_KEY,
        'client_secret': AUTH0_CLIENT_SECRET,
        'request_token_params': {
            'scope': 'email openid profile'
        },
        'response_type': 'token_id',
        'base_url': AUTH0_URL,
        'access_token_url': os.path.join(AUTH0_URL, 'oauth/token'),
        'authorize_url': os.path.join(AUTH0_URL, 'authorize'),
        'access_token_method':'POST',
        'request_token_url': os.path.join(AUTH0_URL, 'oauth/token'),
        'api_base_url': AUTH0_URL,
        }
    }
]

CUSTOM_SECURITY_MANAGER = CustomSsoSecurityManager

I have already tried different values for the response_type (code, token, token_id).

Also tried to leave request_token_url empty and in that case the error changes because the user data appear to be an empty dictionary:

2021-10-13 15:52:10,358:WARNING:superset_config: user_data: {}
2021-10-13 15:52:10,358:WARNING:root:user_data: {}
2021-10-13 15:52:10,358:ERROR:flask_appbuilder.security.views:Error returning OAuth user info: 'email'

So I assume the token is actually returned and I cannot understand why Flask is complaining about the attribute "scope".

Tried this too, since it looked like very similar to my problem, but none of those configurations work for me.

TylerH
  • 20,799
  • 66
  • 75
  • 101
MariusPontmercy
  • 398
  • 1
  • 5
  • 20

3 Answers3

0

Hope you have two files as custom_sso_security_manager.py and superset_config.py

Can you remove below two line from return and try(custom_sso_security_manager.py).

'first_name': me['given_name'],
'last_name': me['family_name'],
TylerH
  • 20,799
  • 66
  • 75
  • 101
Sathish
  • 151
  • 2
  • 10
  • Hi Satish, all the code is in the same file superset_config.py and, as I said, the same configuration is currently working in another Superset deployment authenticating against AWS Cognito. I tried to remove the two items from the user data dictionary but it throws the same error: "got an unexpected keyword argument 'scope'" which happens in a different part of the code. – MariusPontmercy Oct 21 '21 at 09:53
0

This is for future reference, although I accepted Kamal's answer.

It turned out that the right parameter to set the request token scopes was client_kwargs instead of request_token_params.

This is a working configuration to authenticate Superset against Auth0:

## Enable OAuth authentication
from flask_appbuilder.security.manager import (
    AUTH_OAUTH,
)

from superset.security import SupersetSecurityManager

import json
import logging
import string
import random

nonce = ''.join(random.choices(string.ascii_uppercase + string.digits + string.ascii_lowercase, k = 30))

logger = logging.getLogger(__name__)

class CustomSsoSecurityManager(SupersetSecurityManager):
    def oauth_user_info(self, provider, response=None):
        if provider == 'auth0':
            res = self.appbuilder.sm.oauth_remotes[provider].get('userinfo')
            if res.raw.status != 200:
                logger.error('Failed to obtain user info: %s', res.json())
                return
            me = res.json()
            return {
                'username' : me['email'],
                'name' : me['name'],
                'email' : me['email'],
            }

AUTH_TYPE = AUTH_OAUTH
AUTH_USER_REGISTRATION = True
AUTH_USER_REGISTRATION_ROLE = "Public"

AUTH0_URL = os.getenv('AUTH0_URL')
AUTH0_CLIENT_KEY = os.getenv('AUTH0_CLIENT_KEY')
AUTH0_CLIENT_SECRET = os.getenv('AUTH0_CLIENT_SECRET')

OAUTH_PROVIDERS = [
  {   'name':'auth0',
      'token_key':'access_token',
      'icon':'fa-at',
      'remote_app': {
          'api_base_url': AUTH0_URL,
          'client_id': AUTH0_CLIENT_KEY,  
          'client_secret': AUTH0_CLIENT_SECRET, 
          'server_metadata_url': os.path.join(AUTH0_URL, '.well-known/openid-configuration'),
          'client_kwargs': {
              'scope': 'openid profile email'
          },
         'response_type': 'code token',
         'nonce': nonce,
      }
  }
]

CUSTOM_SECURITY_MANAGER = CustomSsoSecurityManager
MariusPontmercy
  • 398
  • 1
  • 5
  • 20
-1

As per Flask Documentation, try to use client_kwargs instead of request_token_params key.

Sample:

{
    'name':'google',
    'icon':'fa-google',
    'token_key':'access_token',
    'remote_app': {
            'client_id':'GOOGLE_KEY',
            'client_secret':'GOOGLE_SECRET',
            'api_base_url':'https://www.googleapis.com/oauth2/v2/',
            'client_kwargs':{
              'scope': 'email profile'
            },
            'request_token_url':None,
            'access_token_url':'https://accounts.google.com/o/oauth2/token',
            'authorize_url':'https://accounts.google.com/o/oauth2/auth'
    }
},
Kamal
  • 2,384
  • 1
  • 13
  • 25
  • Oh my goodness, it worked! Thank you so much Kamal! Going to update my question with the complete working configuration for future reference. Just cannot understand why there are tons of Flask/Superset guides using request_token_params to set the scopes... – MariusPontmercy Oct 27 '21 at 14:17
  • My guess is that those guides are old, and flask may have updated the key name. So always better to confirm at official sites. – Kamal Oct 28 '21 at 03:40