From a1ad4be61efa4bfd325f057ef410f76a56525a33 Mon Sep 17 00:00:00 2001 From: Xiyuan Chen <52963600+GareArc@users.noreply.github.com> Date: Thu, 4 Jun 2026 19:56:23 -0700 Subject: [PATCH] fix(api): expose device-flow approve rate limit as env var (#37083) --- api/configs/feature/__init__.py | 5 +++++ api/controllers/openapi/oauth_device.py | 6 +++--- api/libs/rate_limit.py | 6 +++++- docker/envs/core-services/shared.env.example | 1 + 4 files changed, 14 insertions(+), 4 deletions(-) diff --git a/api/configs/feature/__init__.py b/api/configs/feature/__init__.py index 5083bb11f6..109ce749a6 100644 --- a/api/configs/feature/__init__.py +++ b/api/configs/feature/__init__.py @@ -949,6 +949,11 @@ class AuthConfig(BaseSettings): default=60, ) + DEVICE_FLOW_APPROVE_RATE_LIMIT_PER_HOUR: PositiveInt = Field( + description="Max device-flow approve requests per session per hour on /openapi/oauth/device/approve.", + default=10, + ) + class ModerationConfig(BaseSettings): """ diff --git a/api/controllers/openapi/oauth_device.py b/api/controllers/openapi/oauth_device.py index d685d1fb29..e061f36a6b 100644 --- a/api/controllers/openapi/oauth_device.py +++ b/api/controllers/openapi/oauth_device.py @@ -49,8 +49,8 @@ from extensions.ext_redis import redis_client from libs.helper import extract_remote_ip from libs.oauth_bearer import MINTABLE_PROFILES, SubjectType, bearer_feature_required from libs.rate_limit import ( - LIMIT_APPROVE_CONSOLE, LIMIT_DEVICE_CODE_PER_IP, + LIMIT_DEVICE_FLOW_APPROVE, LIMIT_LOOKUP_PUBLIC, rate_limit, ) @@ -210,7 +210,7 @@ class DeviceApproveApi(Resource): @login_required @account_initialization_required @bearer_feature_required - @rate_limit(LIMIT_APPROVE_CONSOLE) + @rate_limit(LIMIT_DEVICE_FLOW_APPROVE) @with_current_user @with_current_tenant_id def post(self, tenant: str, account: Account): @@ -287,7 +287,7 @@ class DeviceDenyApi(Resource): @login_required @account_initialization_required @bearer_feature_required - @rate_limit(LIMIT_APPROVE_CONSOLE) + @rate_limit(LIMIT_DEVICE_FLOW_APPROVE) def post(self): payload = _validate_json(DeviceMutateRequest) user_code = payload.user_code.strip().upper() diff --git a/api/libs/rate_limit.py b/api/libs/rate_limit.py index 4dad6bff1d..68147f21cf 100644 --- a/api/libs/rate_limit.py +++ b/api/libs/rate_limit.py @@ -40,7 +40,11 @@ class RateLimit: LIMIT_DEVICE_CODE_PER_IP = RateLimit(60, timedelta(hours=1), (RateLimitScope.IP,)) LIMIT_SSO_INITIATE_PER_IP = RateLimit(60, timedelta(hours=1), (RateLimitScope.IP,)) LIMIT_APPROVE_EXT_PER_EMAIL = RateLimit(10, timedelta(hours=1), (RateLimitScope.SUBJECT_EMAIL,)) -LIMIT_APPROVE_CONSOLE = RateLimit(10, timedelta(hours=1), (RateLimitScope.SESSION,)) +LIMIT_DEVICE_FLOW_APPROVE = RateLimit( + limit=dify_config.DEVICE_FLOW_APPROVE_RATE_LIMIT_PER_HOUR, + window=timedelta(hours=1), + scopes=(RateLimitScope.SESSION,), +) LIMIT_LOOKUP_PUBLIC = RateLimit(60, timedelta(minutes=5), (RateLimitScope.IP,)) LIMIT_ME_PER_ACCOUNT = RateLimit(60, timedelta(minutes=1), (RateLimitScope.ACCOUNT,)) LIMIT_ME_PER_EMAIL = RateLimit(60, timedelta(minutes=1), (RateLimitScope.SUBJECT_EMAIL,)) diff --git a/docker/envs/core-services/shared.env.example b/docker/envs/core-services/shared.env.example index 78e050cace..49a8d9bbaa 100644 --- a/docker/envs/core-services/shared.env.example +++ b/docker/envs/core-services/shared.env.example @@ -225,6 +225,7 @@ OPENAPI_ENABLED=false OPENAPI_CORS_ALLOW_ORIGINS= OPENAPI_KNOWN_CLIENT_IDS=difyctl OPENAPI_RATE_LIMIT_PER_TOKEN=60 +DEVICE_FLOW_APPROVE_RATE_LIMIT_PER_HOUR=10 ENABLE_OAUTH_BEARER=false DSL_EXPORT_ENCRYPT_DATASET_ID=true DATASET_MAX_SEGMENTS_PER_REQUEST=0