Flask-OAuthlib
Flask-OAuthlib is an extension for Flask that provides both OAuth client and provider functionalities, built upon the `oauthlib` core. It supports OAuth 1.0a and OAuth 2.0. The library's last release was 0.9.6 in September 2020. It is officially deprecated and not actively maintained; users are strongly encouraged to migrate to `Authlib` for current and future projects.
Common errors
-
ERROR: flask-oauthlib 0.9.5 has requirement oauthlib!=2.0.3,!=2.0.4,!=2.0.5,<3.0.0,>=1.1.2, but you'll have oauthlib 3.1.0 which is incompatible.
cause Conflicting `oauthlib` version requirements when `flask-oauthlib` is installed alongside `requests-oauthlib` or other libraries that demand a newer `oauthlib` version. `flask-oauthlib` is incompatible with `oauthlib >= 3.0.0`.fixThe recommended solution is to migrate to `Authlib`. If migration is not immediately possible, explicitly pin `oauthlib` and `requests-oauthlib` to compatible older versions: `pip install -I oauthlib==2.1.0 requests-oauthlib==1.1.0`. -
Access denied: reason=..., error=Missing access credentials.
cause This error typically indicates that the OAuth provider did not receive or accept the requested scopes, or that the client application lacks necessary permissions. A common reason is an omitted or incorrect `scope` parameter during the authorization request.fixEnsure that the `request_token_params={'scope': '...'}` is correctly defined when setting up `remote_app` or passed to the `authorize()` call, including all necessary scopes for the OAuth provider. Verify your client application's configuration on the OAuth provider's side.
Warnings
- breaking Flask-OAuthlib is officially deprecated and no longer maintained. Active development and support have shifted to the `Authlib` library. Continuing to use Flask-OAuthlib may expose your application to unpatched security vulnerabilities or compatibility issues with newer Python/Flask versions.
- breaking There are known version conflicts between `flask-oauthlib` (which requires `oauthlib < 3.0.0`) and `requests-oauthlib` (which requires `oauthlib >= 3.0.0`). Installing both in the same environment often leads to dependency resolution errors.
- deprecated The `@authorized_handler` decorator for handling OAuth callbacks was deprecated in version 0.7 in favor of the `authorized_response()` method. While still functional in 0.9.x, it's best to update.
- gotcha For OAuth2 client flows, ensure you specify a `scope` in `request_token_params` during `remote_app` configuration or in the `authorize` call. Omitting it can lead to 'Missing access credentials' or similar errors from the OAuth provider.
Install
-
pip install Flask-OAuthlib
Imports
- OAuth
from flask_oauthlib import OAuth
from flask_oauthlib.client import OAuth
- OAuth1Provider
from flask_oauthlib.provider import OAuth1Provider
- OAuth2Provider
from flask_oauthlib.provider import OAuth2Provider
Quickstart
import os
from flask import Flask, redirect, url_for, session, request
from flask_oauthlib.client import OAuth
app = Flask(__name__)
app.debug = True
app.secret_key = 'development'
# NOTE: For local development over HTTP, you might need:
# os.environ['OAUTHLIB_INSECURE_TRANSPORT'] = '1'
# Configure your remote application details
# Replace with your actual consumer_key and consumer_secret
# These values should ideally come from environment variables for production
REMOTE_APP_CLIENT_ID = os.environ.get('REMOTE_APP_CLIENT_ID', 'your_client_id')
REMOTE_APP_CLIENT_SECRET = os.environ.get('REMOTE_APP_CLIENT_SECRET', 'your_client_secret')
# Initialize OAuth
oauth = OAuth(app)
remote_service = oauth.remote_app(
'remote_service',
consumer_key=REMOTE_APP_CLIENT_ID,
consumer_secret=REMOTE_APP_CLIENT_SECRET,
base_url='https://api.example.com/',
request_token_url=None, # Not needed for OAuth2 client credentials or implicit grant
request_token_params={'scope': 'email profile'},
access_token_url='https://example.com/oauth/token',
authorize_url='https://example.com/oauth/authorize',
# Example using a tokengetter/tokensetter for persistent storage
# In a real app, this would store tokens in a database associated with a user
access_token_method='POST'
)
@remote_service.tokengetter
def get_remote_service_token():
return session.get('remote_service_oauth_token')
@app.route('/')
def index():
if 'remote_service_oauth_token' in session:
resp = remote_service.get('userinfo') # Example API call
return f'Logged in as {resp.data.get("email")}<br><a href="/logout">Logout</a>'
return '<p>Hello! <a href="/login">Login with Remote Service</a></p>'
@app.route('/login')
def login():
return remote_service.authorize(callback=url_for('authorized', _external=True))
@app.route('/logout')
def logout():
session.pop('remote_service_oauth_token', None)
return redirect(url_for('index'))
@app.route('/authorized')
def authorized():
resp = remote_service.authorized_response()
if resp is None or resp.get('access_token') is None:
return f'Access denied: reason={request.args["error"]}, error={request.args["error_description"]}'
session['remote_service_oauth_token'] = (resp['access_token'], '') # OAuth2 bearer token, secret is empty
return redirect(url_for('index'))
if __name__ == '__main__':
app.run(port=5000)