My goal is to implement this: https://github.com/Azure-Samples/active-directory-python-flask-graphapi-web-v2
With the newer Authlib library. https://github.com/lepture/authlib
I need an app that authenticates with a certificate (no user login) and grabs data from an Azure AD (v2.0 endpoint) SharePoint Document library using Microsoft's Graph API.
This is the original code using 'flask_oauthlib':
from flask import Flask, redirect, url_for, session, request, jsonify, render_template
from flask_oauthlib.client import OAuth, OAuthException
# from flask_sslify import SSLify
from logging import Logger
import uuid
app = Flask(__name__)
# sslify = SSLify(app)
app.debug = True
app.secret_key = 'development'
oauth = OAuth(app)
# Put your consumer key and consumer secret into a config file
# and don't check it into github!!
microsoft = oauth.remote_app(
    'microsoft',
    consumer_key='Register your app at apps.dev.microsoft.com',
    consumer_secret='Register your app at apps.dev.microsoft.com',
    request_token_params={'scope': 'offline_access User.Read'},
    base_url='https://graph.microsoft.com/v1.0/',
    request_token_url=None,
    access_token_method='POST',
    access_token_url='https://login.microsoftonline.com/common/oauth2/v2.0/token',
    authorize_url='https://login.microsoftonline.com/common/oauth2/v2.0/authorize'
)
@app.route('/')
def index():
    return render_template('hello.html')
@app.route('/login', methods = ['POST', 'GET'])
def login():
    if 'microsoft_token' in session:
        return redirect(url_for('me'))
    # Generate the guid to only accept initiated logins
    guid = uuid.uuid4()
    session['state'] = guid
    return microsoft.authorize(callback=url_for('authorized', _external=True), state=guid)
@app.route('/logout', methods = ['POST', 'GET'])
def logout():
    session.pop('microsoft_token', None)
    session.pop('state', None)
    return redirect(url_for('index'))
@app.route('/login/authorized')
def authorized():
    response = microsoft.authorized_response()
    if response is None:
        return "Access Denied: Reason=%s\nError=%s" % (
            response.get('error'),
            request.get('error_description')
        )
    # Check response for state
    print("Response: " + str(response))
    if str(session['state']) != str(request.args['state']):
        raise Exception('State has been messed with, end authentication')
    # Okay to store this in a local variable, encrypt if it's going to client
    # machine or database. Treat as a password.
    session['microsoft_token'] = (response['access_token'], '')
    return redirect(url_for('me'))
@app.route('/me')
def me():
    me = microsoft.get('me')
    return render_template('me.html', me=str(me.data))
# If library is having trouble with refresh, uncomment below and implement refresh handler
# see https://github.com/lepture/flask-oauthlib/issues/160 for instructions on how to do this
# Implements refresh token logic
# @app.route('/refresh', methods=['POST'])
# def refresh():
@microsoft.tokengetter
def get_microsoft_oauth_token():
    return session.get('microsoft_token')
if __name__ == '__main__':
    app.run()
Here is the code I have updated so far to 'authlib.flask':
from flask import Flask
from flask import redirect, url_for, session, request, jsonify, render_template
from authlib.flask.client import OAuth
from logging import Logger
import uuid
app = Flask(__name__)
app.debug = True
app.secret_key = 'development'
oauth = OAuth(app)
# Put your consumer key and consumer secret into a config file
    # and don't check it into github!!
microsoft = oauth.register(
    'microsoft',
    client_id='Register your app at apps.dev.microsoft.com',
    client_secret='Register your app at apps.dev.microsoft.com',
    request_token_params={'scope': 'offline_access User.Read'},
    api_base_url='https://graph.microsoft.com/v1.0/',
    request_token_url=None,
    access_token_method='POST',
    access_token_url='https://login.microsoftonline.com/common/oauth2/v2.0/token',
    authorize_url='https://login.microsoftonline.com/common/oauth2/v2.0/authorize',
)
@app.route('/')
def index():
    return render_template('hello.html')
@app.route('/login', methods = ['POST', 'GET'])
def login():
    if 'microsoft_token' in session:
        return redirect(url_for('me'))
    # Generate the guid to only accept initiated logins
    guid0 = uuid.uuid4()
    guid = guid0.bytes
    session['state'] = guid
    return microsoft.authorize_redirect(url_for('authorized', _external=True), state=guid)
@app.route('/logout', methods = ['POST', 'GET'])
def logout():
    session.pop('microsoft_token', None)
    session.pop('state', None)
    return redirect(url_for('index'))
@app.route('/login/authorized')
def authorized():
    response = microsoft.authorize_access_token()
    if response is None:
        return "Access Denied: Reason=%s\nError=%s" % (
            response.get('error'),
            request.get('error_description')
        )
    # Check response for state
    print("Response: " + str(response))
    if str(session['state']) != str(request.args['state']):
        raise Exception('State has been messed with, end authentication')
    # Okay to store this in a local variable, encrypt if it's going to client
    # machine or database. Treat as a password.
    session['microsoft_token'] = (response['access_token'], '')
    return redirect(url_for('me'))
@app.route('/me')
def me():
    me = microsoft.get('me')
    return render_template('me.html', me=str(me.data))
# If library is having trouble with refresh, uncomment below and implement refresh handler
# see https://github.com/lepture/flask-oauthlib/issues/160 for instructions on how to do this
# Implements refresh token logic
# @app.route('/refresh', methods=['POST'])
# def refresh():
@microsoft.tokengetter
def get_microsoft_oauth_token():
    return session.get('microsoft_token')
if __name__ == '__main__':
    app.run()
The part I am stuck on is what to do with:
@microsoft.tokengetter
def get_microsoft_oauth_token():
    return session.get('microsoft_token')
The Authlib documentation from 'Migrate OAuth Client from Flask-OAuthlib to Authlib' states the following:
If you want to access resource with methods like oauth.twitter.get(...), you will need to make sure there is a ready to use access token. This part is very different between Flask-OAuthlib and Authlib.
In Flask-OAuthlib, it is handled by a decorator:
 @twitter.tokengetter
 def get_twitter_oauth_token():
     token = fetch_from_somewhere()
     return token
The token returned by tokengetter can be a tuple or a dict. But in Authlib, it can only be a dict, and Authlib doesn't use a decorator to fetch token, instead, you should pass this function to the registry:
 # register the two methods oauth.register('twitter',
     client_id='Twitter Consumer Key',
     client_secret='Twitter Consumer Secret',
     request_token_url='https://api.twitter.com/oauth/request_token',
     request_token_params=None,
     access_token_url='https://api.twitter.com/oauth/access_token',
     access_token_params=None,
     refresh_token_url=None,
     authorize_url='https://api.twitter.com/oauth/authenticate',
     api_base_url='https://api.twitter.com/1.1/',
     client_kwargs=None,
     # NOTICE HERE
     fetch_token=fetch_twitter_token,
     save_request_token=save_request_token,
     fetch_request_token=fetch_request_token, )
https://blog.authlib.org/2018/migrate-flask-oauthlib-client-to-authlib
I have no idea what to do with '@microsoft.tokengetter'
Does anyone have any suggestions?
                        
Checkout the documentation at http://docs.authlib.org/en/latest/flask/client.html#flask-client
Here are some invalid code in your question: