Flask-OpenID
Flask-OpenID is a Flask extension that provides OpenID 1.x and 2.x authentication support for web applications. The current version is 1.3.1, released in 2021. It is in maintenance mode, primarily for existing applications, as the OpenID Connect standard has largely superseded OpenID 1/2 for new development.
Warnings
- gotcha Flask-OpenID exclusively supports OpenID 1.x and 2.x standards, NOT the more modern OpenID Connect (OIDC). If you need OIDC support, consider libraries like Flask-OIDC, Authlib, or direct integration with OAuth2/OIDC providers.
- breaking Version 1.3.0 and later of Flask-OpenID are Python 3-only. Support for Python 2.x was dropped.
- gotcha The `SECRET_KEY` configuration is critical for session security. Using a weak or default key like 'a_very_secret_key_for_dev' in production is a severe security risk.
- deprecated Given the deprecation of OpenID 1.x/2.x in favor of OpenID Connect, Flask-OpenID is largely considered a legacy solution. It is not actively developed for new features or modern security enhancements related to current web authentication standards.
Install
-
pip install flask-openid
Imports
- OpenID
from flask_openid import OpenID
Quickstart
import os
from flask import Flask, render_template, session, request, redirect, url_for
from flask_openid import OpenID
app = Flask(__name__)
app.config.update(
SECRET_KEY=os.environ.get('FLASK_SECRET_KEY', 'a_very_secret_key_for_dev'), # CHANGE THIS FOR PROD
OPENID_FS_STORE=os.path.join(os.path.dirname(__file__), 'tmp', 'openid_store')
)
oid = OpenID(app)
@app.route('/')
@oid.loginhandler
def index():
if oid.fetch_user():
return f'Hello, {session["name"]}! <p><a href="{url_for("logout")}">Logout</a></p>'
return render_template('login.html', next=oid.get_next_url(), error=oid.fetch_error())
@app.route('/login', methods=['GET', 'POST'])
@oid.loginhandler
def login():
if oid.fetch_user():
return redirect(oid.get_next_url())
if request.method == 'POST':
openid = request.form.get('openid_identifier')
if openid:
return oid.try_login(openid, ask_for=['email', 'nickname'],
ask_for_optional=['fullname'])
return render_template('login.html', next=oid.get_next_url(),
error=oid.fetch_error())
@app.route('/logout')
def logout():
oid.logout()
return redirect(oid.get_next_url())
@oid.after_login
def create_or_login(resp):
session['openid'] = resp.identity_url
session['name'] = resp.fullname or resp.nickname or resp.identity_url
return redirect(oid.get_next_url())
if __name__ == '__main__':
# Create necessary directories and a minimal login.html for the quickstart to run
os.makedirs(app.config['OPENID_FS_STORE'], exist_ok=True)
os.makedirs('templates', exist_ok=True)
with open('templates/login.html', 'w') as f:
f.write('''
<!doctype html>
<html>
<head><title>Login</title></head>
<body>
<h1>Login with OpenID</h1>
{% if error %}<p style="color: red;">Error: {{ error }}</p>{% endif %}
<form action="{{ url_for('login') }}" method="post">
<dl>
<dt>OpenID:</dt>
<dd><input type="text" name="openid_identifier" value="" placeholder="e.g. https://openid.aol.com/yourusername" /></dd>
<dd><input type="submit" value="Login" /></dd>
</dl>
</form>
<p><a href="{{ url_for('logout') }}">Logout</a></p>
</body>
</html>
''')
app.run(debug=True)