OAuth using Python Flask OAuthlib

Dear

I have a flask app (Airflow) and I wrote a generic oauth module that worked fine with Github but Okta returned

400: Bad Request
BAD REQUEST

Your request resulted in an error.
Go to Homepage
Identity Provider: Unknown
Error Code: invalid_request
Description: The ‘redirect_uri’ parameter must be an absolute URI that is whitelisted in the client app settings.

I already added my domain and all possible links to Trusted Origin (CORS and Redirect) also added them in Login redirect URIs in the App Configurations

Same module works fine with Github by changing the urls and client id and client secret

import flask_login

# Need to expose these downstream
# pylint: disable=unused-import
from flask_login import (current_user,
                     logout_user,
                     login_required,
                     login_user)
# pylint: enable=unused-import

from flask import url_for, redirect, request

from flask_oauthlib.client import OAuth

from airflow import models, configuration, settings
from airflow.configuration import AirflowConfigException
from airflow.utils.log.logging_mixin import LoggingMixin
from airflow.exceptions import AirflowConfigException

_log = LoggingMixin().log


def get_config_param(param):
try:
    return str(configuration.get('generic_oauth', param))
except AirflowConfigException:
    return None


class GenericOAuthUser(models.User):

def __init__(self, user):
    self.user = user

def is_active(self):
    '''Required by flask_login'''
    return True

def is_authenticated(self):
    '''Required by flask_login'''
    return True

def is_anonymous(self):
    '''Required by flask_login'''
    return False

def get_id(self):
    '''Returns the current user id as required by flask_login'''
    return self.user.get_id()

def data_profiling(self):
    '''Provides access to data profiling tools'''
    return True

def is_superuser(self):
    '''Access all the things'''
    return True


class AuthenticationError(Exception):
pass


class GenericOAuthBackend(object):

def __init__(self):
    self.login_manager = flask_login.LoginManager()
    self.login_manager.login_view = 'airflow.login'
    self.flask_app = None
    self.oauth = None
    self.base_url = get_config_param('base_url')
    self.oauth_url = get_config_param('oauth_url')
    self.access_token_url = get_config_param('access_token_url')
    self.request_token_url = get_config_param('request_token_url')
    self.client_id = get_config_param('client_id')
    self.client_secret = get_config_param('client_secret')
    self.scopes = get_config_param('scopes') # openid,profile,email
    self.provider_name = get_config_param('provider_name')
    self.oauth_callback_url = get_config_param('callback_url')
    self.oauth_user_info_url = get_config_param('user_info_url')

def init_app(self, flask_app):
    self.flask_app = flask_app

    self.login_manager.init_app(self.flask_app)

    self.oauth = OAuth(self.flask_app).remote_app(
        self.provider_name,
        consumer_key=self.client_id,
        consumer_secret=self.client_secret,
        # need read:org to get team member list
        request_token_params={'scope': self.scopes},
        base_url=self.base_url,
        request_token_url=self.request_token_url,
        access_token_method='POST',
        access_token_url=self.access_token_url,
        authorize_url=self.oauth_url
    )

    self.login_manager.user_loader(self.load_user)
    self.flask_app.add_url_rule(self.oauth_callback_url or '/oauth-callback', 'generic_oauth_callback', self.oauth_callback)

def login(self, request):
    _log.info('Redirecting user to OAuth login')
    return self.oauth.authorize(callback=url_for('generic_oauth_callback',
                                                 _scheme='https',
                                                 _external=True, next=request.args.get('next') or request.referrer or None))

def get_user_profile_info(self, token):
    resp = self.oauth.get(self.oauth_user_info_url, token=(token, ''))

    if not resp or resp.status != 200:
        raise AuthenticationError(
            'Failed to fetch user profile, status ({0})'.format(
                resp.status if resp else 'None'))

    return resp.data['login'], resp.data['email']

def load_user(self, userid):
    if not userid or userid == 'None':
        return None

    session = settings.Session()
    user = session.query(models.User).filter(
        models.User.id == int(userid)).first()
    session.expunge_all()
    session.commit()
    session.close()
    return GenericOAuthUser(user)

def oauth_callback(self):
    _log.info('OAuth callback called')

    next_url = request.args.get('next') or url_for('admin.index')

    resp = self.oauth.authorized_response()

    _log.info(resp)

    try:
        if resp is None:
            raise AuthenticationError(
                'Null response from %s, denying access.' % self.provider_name
            )

        access_token = resp['access_token']

        username, email = self.get_user_profile_info(access_token)

    except AuthenticationError:
        _log.exception('')
        return redirect(url_for('airflow.noaccess'))

    session = settings.Session()

    user = session.query(models.User).filter(
        models.User.username == username).first()

    if not user:
        user = models.User(
            username=username,
            email=email,
            is_superuser=False)

    session.merge(user)
    session.commit()
    login_user(GenericOAuthUser(user))
    session.commit()
    session.close()

    return redirect(next_url)


login_manager = GenericOAuthBackend()


def login(self, request):
return login_manager.login(request)

this is returning None in the code when setup with Okta

resp = self.oauth.authorized_response()

my redirect URI / callback / Login Initiate URI are

https://domain.com/oauth-callback

and I configured the module with the following

Hey wahb,

Planning to setup Okta OAuth for our Airflow app as well. Were you able to do this successfully?

Stan