From 0e9dc86f3b48efcfdb381d1f4ded5955bfd7db52 Mon Sep 17 00:00:00 2001 From: GareArc Date: Wed, 4 Mar 2026 20:30:53 -0800 Subject: [PATCH] fix: use UnauthorizedAndForceLogout to trigger frontend logout on license expiry Change license check to raise UnauthorizedAndForceLogout exception instead of returning generic JSON response. This ensures proper frontend handling: Frontend behavior (service/base.ts line 588): - Checks if code === 'unauthorized_and_force_logout' - Executes globalThis.location.reload() - Forces user logout and redirect to login page - Login page displays license expiration UI (already exists) Response format: - HTTP 401 (not 403) - code: "unauthorized_and_force_logout" - Triggers frontend reload which clears auth state This completes the license enforcement flow: 1. Backend blocks all business APIs when license expires 2. Backend returns proper error code to trigger logout 3. Frontend reloads and redirects to login 4. Login page shows license expiration message --- api/app_factory.py | 20 +++++++++++--------- 1 file changed, 11 insertions(+), 9 deletions(-) diff --git a/api/app_factory.py b/api/app_factory.py index c846e56f2f..883a30d9c9 100644 --- a/api/app_factory.py +++ b/api/app_factory.py @@ -1,12 +1,13 @@ import logging import time -from flask import jsonify, request +from flask import request from opentelemetry.trace import get_current_span from opentelemetry.trace.span import INVALID_SPAN_ID, INVALID_TRACE_ID from configs import dify_config from contexts.wrapper import RecyclableContextVar +from controllers.console.error import UnauthorizedAndForceLogout from core.logging.context import init_request_context from dify_app import DifyApp from services.feature_service import FeatureService, LicenseStatus @@ -61,14 +62,15 @@ def create_flask_app_with_configs() -> DifyApp: LicenseStatus.EXPIRED, LicenseStatus.LOST, ]: - return jsonify({ - "code": "license_expired", - "message": ( - f"Enterprise license is {system_features.license.status.value}. " - "Please contact your administrator." - ), - "status": system_features.license.status.value, - }), 403 + # Raise UnauthorizedAndForceLogout to trigger frontend reload and logout + # Frontend checks code === 'unauthorized_and_force_logout' and calls location.reload() + raise UnauthorizedAndForceLogout( + f"Enterprise license is {system_features.license.status.value}. " + "Please contact your administrator." + ) + except UnauthorizedAndForceLogout: + # Re-raise to let Flask error handler convert to proper JSON response + raise except Exception: # If license check fails, log but don't block the request # This prevents service disruption if enterprise API is temporarily unavailable