Apache Superset returns "unexpected keyword argument 'scope'"

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.

Thank you for your help

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

We found that that this response was correct but you need to omit ‘response_type’:

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