Migrate OAuth Client from Flask-OAuthlib to Authlib

A guide on how to migrate OAuth client from Flask-OAuthlib to Authlib, and why.

Flask-OAuthlib is deprecated in favor of Authlib. Here is a guide on how to migrate OAuth client from Flask-OAuthlib to Authlib. If you are new to Flask-OAuthlib, you don't have to read this post, instead, just head over to Authlib Documentation on Flask Client.

Why Authlib

The OAuth client implementation in Flask-OAuthlib is very bad. I didn't mean the API design, oh, the API methods are quite good, and Authlib shares a similar API. However, Flask-OAuthlib is using the built-in urllib2 or urllib, which makes things terrible.

There was once a plan to replace them with requests, but it didn't happen until I made the new Authlib, which is another story. The client part is powered by requests in Authlib, which handles http well and correct.

Initialize

We will focus on the differences between Flask-OAuthlib and the Flask integration in Authlib. Although Authlib has Django integration as well.

The oauth registries are similar, but with different parameters:

from flask_oauthlib.client import OAuth
oauth = OAuth(app)

twitter = oauth.remote_app('twitter',
    base_url='https://api.twitter.com/1.1/',
    request_token_url='https://api.twitter.com/oauth/request_token',
    access_token_url='https://api.twitter.com/oauth/access_token',
    authorize_url='https://api.twitter.com/oauth/authenticate',
    consumer_key='<your key here>',
    consumer_secret='<your secret here>'
)
from authlib.flask.client import OAuth
oauth = OAuth(app)
twitter = oauth.register('twitter',
    client_id='Twitter Consumer Key',
    client_secret='Twitter Consumer Secret',
    request_token_url='https://api.twitter.com/oauth/request_token',
    access_token_url='https://api.twitter.com/oauth/access_token',
    authorize_url='https://api.twitter.com/oauth/authenticate',
    api_base_url='https://api.twitter.com/1.1/',
)

Configuration

Those parameters in .remote_app (Flask-OAuthlib) and .register (Authlib) can be loaded with configurations too. Get the differences in the official documentations:

  1. Flask-OAuthlib Lazy Configuration
  2. Authlib Flask Configuration

Methods

The workflow of an OAuth authorization has two steps both in Flask-OAuthlib and Authlib:

  1. redirect to the service's login page
  2. back to our authenticated page

In Flask-OAuthlib, it looks like:

@app.route('/login')
def login():
    redirect_uri = url_for('authorize', _external=True)
    return oauth.twitter.authorize(callback=redirect_uri)

@app.route('/authorize')
def authorize():
    resp_data = oauth.twitter.authorized_response()
    # do something with response data

In Authlib, it looks like:

@app.route('/login')
def login():
    redirect_uri = url_for('authorize', _external=True)
    return oauth.twitter.authorize_redirect(redirect_uri)

@app.route('/authorize')
def authorize():
    token = oauth.twitter.authorize_access_token()
    # do something with the token

The client parts are very simple, what you need to change is the initialization part and the authorization routes, there is nothing difficult.

Token

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,
)

Please note, that Flask-OAuthlib is saving request token in Flask.session which will expose the request token in HTTP transport. In Authlib, you need to save it in other place, like a cache or database. Find more in Authlib Documentation

Others

There is a authorized_handler decorator in Flask-OAuthlib which is not recommended anymore. This decorator is not in Authlib. You need to call oauth.twitter.authorize_access_token in the route yourself.