Authlib: OAuth & OpenID Connect Library
Authlib is a comprehensive Python library for building OAuth (1.0 & 2.0) and OpenID Connect (OIDC) clients and servers. It includes full support for JSON Web Signatures (JWS), JSON Web Encryption (JWE), JSON Web Keys (JWK), JSON Web Algorithms (JWA), and JSON Web Tokens (JWT). The library is actively maintained with frequent releases, currently at version 1.6.9, and is compatible with Python 3.9+.
Warnings
- gotcha When developing locally without HTTPS, Authlib will raise an `InsecureTransportError` as OAuth 2.0 strictly requires HTTPS. To bypass this for local testing, set the environment variable `AUTHLIB_INSECURE_TRANSPORT` to `1` or `true`. This should NEVER be used in production.
- breaking Authlib v1.0.0 introduced significant breaking changes, including dropping Python 2 support, removing built-in SQLAlchemy integration, and restructuring framework integrations. If using Flask OAuth 2.0 provider, `OAUTH2_JWT_XXX` configurations were removed, requiring developers to define `.get_jwt_config` on OpenID extensions and grant types.
- breaking In Authlib v1.1.0, the default `authlib.jose.jwt` instance was restricted to only work with JSON Web Signature (JWS) algorithms. If you need to use JWT with JSON Web Encryption (JWE) algorithms, you must explicitly pass the `algorithms` parameter to `JsonWebToken`.
- gotcha By default, `authlib.jose.jwt.decode` parses the `alg` header, potentially allowing symmetric MACs (e.g., HS256) and asymmetric signatures (e.g., RS256) to be combined. This can lead to a signature bypass (CVE-2016-10555).
- deprecated The `authlib.jose` module is being split into a separate `joserfc` package. While still part of Authlib v1.x, this indicates a future architectural shift that may lead to breaking changes in `jose` imports or functionality in Authlib v2.x.
Install
-
pip install Authlib -
pip install Authlib requests # For Requests-based OAuth clients -
pip install Authlib httpx # For HTTPX-based async OAuth clients -
pip install Authlib Flask # For Flask integrations
Imports
- OAuth
from authlib.integrations.flask_client import OAuth
- OAuth2Session
from authlib.integrations.requests_client import OAuth2Session
- jwt
from authlib.jose import jwt
- AuthorizationServer
from authlib.integrations.flask_oauth2 import AuthorizationServer
Quickstart
import os
from flask import Flask, redirect, url_for, session, jsonify
from authlib.integrations.flask_client import OAuth
app = Flask(__name__)
app.secret_key = os.environ.get('FLASK_SECRET_KEY', 'super-secret-key')
app.config['GOOGLE_CLIENT_ID'] = os.environ.get('GOOGLE_CLIENT_ID', '')
app.config['GOOGLE_CLIENT_SECRET'] = os.environ.get('GOOGLE_CLIENT_SECRET', '')
app.config['GOOGLE_AUTHORIZE_URL'] = 'https://accounts.google.com/o/oauth2/auth'
app.config['GOOGLE_ACCESS_TOKEN_URL'] = 'https://oauth2.googleapis.com/token'
app.config['GOOGLE_USERINFO_ENDPOINT'] = 'https://openidconnect.googleapis.com/v1/userinfo'
app.config['GOOGLE_JWKS_URI'] = 'https://www.googleapis.com/oauth2/v3/certs'
# Configure a dummy URL for local testing
# In a real app, ensure this is HTTPS and a valid redirect URI configured with your OAuth provider
app.config['GOOGLE_REDIRECT_URI'] = os.environ.get('GOOGLE_REDIRECT_URI', 'http://127.0.0.1:5000/authorize')
oauth = OAuth(app)
oauth.register(
'google',
client_id=app.config['GOOGLE_CLIENT_ID'],
client_secret=app.config['GOOGLE_CLIENT_SECRET'],
authorize_url=app.config['GOOGLE_AUTHORIZE_URL'],
access_token_url=app.config['GOOGLE_ACCESS_TOKEN_URL'],
userinfo_endpoint=app.config['GOOGLE_USERINFO_ENDPOINT'],
jwks_uri=app.config['GOOGLE_JWKS_URI'], # Required for OIDC id_token validation
client_kwargs={'scope': 'openid email profile'}
)
@app.route('/')
def index():
user = session.get('user')
if user:
return f'Hello, {user.get("name", "User")}! <a href="/logout">Logout</a>'
return '<a href="/login">Login with Google</a>'
@app.route('/login')
def login():
redirect_uri = url_for('authorize', _external=True)
return oauth.google.authorize_redirect(redirect_uri)
@app.route('/authorize')
def authorize():
try:
token = oauth.google.authorize_access_token()
userinfo = oauth.google.parse_id_token(token)
session['user'] = userinfo
return redirect('/')
except Exception as e:
return f'Authorization failed: {e}', 400
@app.route('/logout')
def logout():
session.pop('user', None)
return redirect('/')
if __name__ == '__main__':
# For local development, allow insecure transport
# NEVER use in production without proper HTTPS setup
os.environ['AUTHLIB_INSECURE_TRANSPORT'] = '1'
print("To run, set environment variables like:")
print("export FLASK_SECRET_KEY='your-flask-secret-key'")
print("export GOOGLE_CLIENT_ID='YOUR_GOOGLE_CLIENT_ID'")
print("export GOOGLE_CLIENT_SECRET='YOUR_GOOGLE_CLIENT_SECRET'")
print("Then: flask --app YOUR_APP_FILE.py run")
app.run(debug=True)