Authlib: OAuth & OpenID Connect Library
raw JSON → 1.6.9 verified Tue May 12 auth: no python install: verified quickstart: stale
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+.
pip install Authlib Common errors
error ModuleNotFoundError: No module named 'authlib' ↓
cause The 'authlib' package is not installed in the Python environment.
fix
Install the package using 'pip install authlib'.
error AttributeError: 'View' object has no attribute 'get_absolute_uri' ↓
cause The 'ResourceProtector' decorator is applied to a class-based view method, but it expects a function-based view.
fix
Extend 'ResourceProtector' to handle class-based views or use it with function-based views.
error ImportError: cannot import name 'JWTBearerToken' from 'authlib.oauth2.rfc7523' ↓
cause The 'JWTBearerToken' class does not exist in the 'authlib.oauth2.rfc7523' module.
fix
Use 'JWTBearerTokenValidator' from 'authlib.oauth2.rfc7523' instead.
error AttributeError: 'function' object has no attribute 'create_authorization_url' ↓
cause An instance of 'OAuth2Session' is not properly created before calling 'create_authorization_url'.
fix
Ensure 'OAuth2Session' is correctly instantiated before calling its methods.
error authlib.integrations.base_client.errors.MismatchingStateError: mismatching_state: CSRF Warning! State not equal in request and response ↓
cause This error occurs in OAuth 2.0 authorization flows when the 'state' parameter, used for CSRF protection, sent in the initial authorization request does not match the 'state' parameter received in the callback. This is often due to session issues (e.g., session not persisting across redirects, incorrect cookie settings for HTTPS behind a proxy, or `client_id` being `None`).
fix
Verify that your Flask/Starlette session is properly configured and persisting, especially when deployed behind a proxy (e.g., using
ProxyFix for Flask to ensure HTTPS is detected correctly and cookies are marked as Secure; SameSite=None). Ensure client_id and other OAuth client registration parameters are correctly loaded before the OAuth client is registered. 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. ↓
fix Set `os.environ['AUTHLIB_INSECURE_TRANSPORT'] = '1'` in your development environment, or ensure your application is served over HTTPS.
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. ↓
fix Upgrade to Python 3.9+ and refactor client/server integrations according to the new `authlib.integrations` structure. For OAuth 2.0 providers, adapt JWT configuration methods.
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`. ↓
fix For JWE, instantiate `JsonWebToken` with allowed algorithms: `from authlib.jose import JsonWebToken; jwt_instance = JsonWebToken(['A128KW', 'A128GCM', 'DEF'])`.
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). ↓
fix Explicitly restrict allowed algorithms when decoding by instantiating `JsonWebToken` with a list of trusted algorithms, or use a custom key loader that provides different keys for symmetric and asymmetric signatures.
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. ↓
fix Keep an eye on future Authlib major releases for official migration guides. For now, be aware that direct `jose` imports might change or require installing `joserfc` separately in the future.
Install
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 Install compatibility verified last tested: 2026-05-12
python os / libc status wheel install import disk
3.10 alpine (musl) wheel - - 38.0M
3.10 alpine (musl) - - - -
3.10 alpine (musl) - - - -
3.10 alpine (musl) - - - -
3.10 alpine (musl) - - - -
3.10 alpine (musl) - - - -
3.10 alpine (musl) - - - -
3.10 alpine (musl) - - - -
3.10 slim (glibc) wheel 2.7s - 38M
3.10 slim (glibc) - - - -
3.10 slim (glibc) - - - -
3.10 slim (glibc) - - - -
3.10 slim (glibc) - - - -
3.10 slim (glibc) - - - -
3.10 slim (glibc) - - - -
3.10 slim (glibc) - - - -
3.11 alpine (musl) wheel - - 40.4M
3.11 alpine (musl) - - - -
3.11 alpine (musl) - - - -
3.11 alpine (musl) - - - -
3.11 alpine (musl) - - - -
3.11 alpine (musl) - - - -
3.11 alpine (musl) - - - -
3.11 alpine (musl) - - - -
3.11 slim (glibc) wheel 2.5s - 41M
3.11 slim (glibc) - - - -
3.11 slim (glibc) - - - -
3.11 slim (glibc) - - - -
3.11 slim (glibc) - - - -
3.11 slim (glibc) - - - -
3.11 slim (glibc) - - - -
3.11 slim (glibc) - - - -
3.12 alpine (musl) wheel - - 32.1M
3.12 alpine (musl) - - - -
3.12 alpine (musl) - - - -
3.12 alpine (musl) - - - -
3.12 alpine (musl) - - - -
3.12 alpine (musl) - - - -
3.12 alpine (musl) - - - -
3.12 alpine (musl) - - - -
3.12 slim (glibc) wheel 2.3s - 33M
3.12 slim (glibc) - - - -
3.12 slim (glibc) - - - -
3.12 slim (glibc) - - - -
3.12 slim (glibc) - - - -
3.12 slim (glibc) - - - -
3.12 slim (glibc) - - - -
3.12 slim (glibc) - - - -
3.13 alpine (musl) wheel - - 31.9M
3.13 alpine (musl) - - - -
3.13 alpine (musl) - - - -
3.13 alpine (musl) - - - -
3.13 alpine (musl) - - - -
3.13 alpine (musl) - - - -
3.13 alpine (musl) - - - -
3.13 alpine (musl) - - - -
3.13 slim (glibc) wheel 2.3s - 32M
3.13 slim (glibc) - - - -
3.13 slim (glibc) - - - -
3.13 slim (glibc) - - - -
3.13 slim (glibc) - - - -
3.13 slim (glibc) - - - -
3.13 slim (glibc) - - - -
3.13 slim (glibc) - - - -
3.9 alpine (musl) wheel - - 37.3M
3.9 alpine (musl) - - - -
3.9 alpine (musl) - - - -
3.9 alpine (musl) - - - -
3.9 alpine (musl) - - - -
3.9 alpine (musl) - - - -
3.9 alpine (musl) - - - -
3.9 alpine (musl) - - - -
3.9 slim (glibc) wheel 3.4s - 38M
3.9 slim (glibc) - - - -
3.9 slim (glibc) - - - -
3.9 slim (glibc) - - - -
3.9 slim (glibc) - - - -
3.9 slim (glibc) - - - -
3.9 slim (glibc) - - - -
3.9 slim (glibc) - - - -
Imports
- OAuth
from authlib.integrations.flask_client import OAuth - OAuth2Session wrong
from authlib.client import OAuth2Sessioncorrectfrom authlib.integrations.requests_client import OAuth2Session - jwt wrong
from authlib.common.jose import jwtcorrectfrom authlib.jose import jwt - AuthorizationServer
from authlib.integrations.flask_oauth2 import AuthorizationServer
Quickstart stale last tested: 2026-04-24
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)