From 84ff594c5785e25c903456f9c06b0a39c5aa9888 Mon Sep 17 00:00:00 2001 From: OpenClaw Auto Backup Date: Thu, 2 Apr 2026 03:06:32 +0800 Subject: [PATCH 1/2] Update Authlib dependency to 1.x for Flask 3.x compatibility Authlib 0.13 imports flask._app_ctx_stack which was removed in Flask 2.3+. Bumping to Authlib>=1.0 resolves the ImportError on modern Flask versions. Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-openagent) Co-authored-by: Sisyphus --- requirements.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/requirements.txt b/requirements.txt index 2813c42..abd0c6b 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,3 +1,3 @@ Flask Flask-SQLAlchemy -Authlib==0.13 +Authlib>=1.0 From a3154d1e2d7b866b22737a07d1bb9e5b4ce35545 Mon Sep 17 00:00:00 2001 From: OpenClaw Auto Backup Date: Thu, 2 Apr 2026 03:06:47 +0800 Subject: [PATCH 2/2] Migrate OAuth2 code to Authlib 1.x API Adapts oauth2.py and routes.py to Authlib 1.x breaking changes: - create_authorization_code -> save_authorization_code (new signature) - parse_authorization_code -> query_authorization_code - validate_consent_request -> get_consent_grant - get_jwt_config now receives client parameter - request object uses .payload and .client attributes - Blueprint name fixed for Flask 3.x (no dots allowed) Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-openagent) Co-authored-by: Sisyphus --- website/oauth2.py | 34 ++++++++++++++++------------------ website/routes.py | 4 ++-- 2 files changed, 18 insertions(+), 20 deletions(-) diff --git a/website/oauth2.py b/website/oauth2.py index 955360c..c3322f7 100644 --- a/website/oauth2.py +++ b/website/oauth2.py @@ -26,9 +26,9 @@ 'exp': 3600, } -def exists_nonce(nonce, req): +def exists_nonce(nonce, request): exists = OAuth2AuthorizationCode.query.filter_by( - client_id=req.client_id, nonce=nonce + client_id=request.payload.client_id, nonce=nonce ).first() return bool(exists) @@ -37,27 +37,25 @@ def generate_user_info(user, scope): return UserInfo(sub=str(user.id), name=user.username) -def create_authorization_code(client, grant_user, request): - code = gen_salt(48) - nonce = request.data.get('nonce') +def save_authorization_code(code, request): + nonce = request.payload.data.get('nonce') item = OAuth2AuthorizationCode( code=code, - client_id=client.client_id, - redirect_uri=request.redirect_uri, - scope=request.scope, - user_id=grant_user.id, + client_id=request.client.client_id, + redirect_uri=request.payload.redirect_uri, + scope=request.payload.scope, + user_id=request.user.id, nonce=nonce, ) db.session.add(item) db.session.commit() - return code class AuthorizationCodeGrant(_AuthorizationCodeGrant): - def create_authorization_code(self, client, grant_user, request): - return create_authorization_code(client, grant_user, request) + def save_authorization_code(self, code, request): + return save_authorization_code(code, request) - def parse_authorization_code(self, code, client): + def query_authorization_code(self, code, client): item = OAuth2AuthorizationCode.query.filter_by( code=code, client_id=client.client_id).first() if item and not item.is_expired(): @@ -75,7 +73,7 @@ class OpenIDCode(_OpenIDCode): def exists_nonce(self, nonce, request): return exists_nonce(nonce, request) - def get_jwt_config(self, grant): + def get_jwt_config(self, grant, client): return DUMMY_JWT_CONFIG def generate_user_info(self, user, scope): @@ -86,7 +84,7 @@ class ImplicitGrant(_OpenIDImplicitGrant): def exists_nonce(self, nonce, request): return exists_nonce(nonce, request) - def get_jwt_config(self, grant): + def get_jwt_config(self, client): return DUMMY_JWT_CONFIG def generate_user_info(self, user, scope): @@ -94,13 +92,13 @@ def generate_user_info(self, user, scope): class HybridGrant(_OpenIDHybridGrant): - def create_authorization_code(self, client, grant_user, request): - return create_authorization_code(client, grant_user, request) + def save_authorization_code(self, code, request): + return save_authorization_code(code, request) def exists_nonce(self, nonce, request): return exists_nonce(nonce, request) - def get_jwt_config(self): + def get_jwt_config(self, client): return DUMMY_JWT_CONFIG def generate_user_info(self, user, scope): diff --git a/website/routes.py b/website/routes.py index 78f135e..8d00452 100644 --- a/website/routes.py +++ b/website/routes.py @@ -8,7 +8,7 @@ from .oauth2 import authorization, require_oauth, generate_user_info -bp = Blueprint(__name__, 'home') +bp = Blueprint('home', __name__) def current_user(): @@ -78,7 +78,7 @@ def authorize(): user = current_user() if request.method == 'GET': try: - grant = authorization.validate_consent_request(end_user=user) + grant = authorization.get_consent_grant(end_user=user) except OAuth2Error as error: return jsonify(dict(error.get_body())) return render_template('authorize.html', user=user, grant=grant)