From 6ef1e017df8871654463d680c11bbdc759a245a8 Mon Sep 17 00:00:00 2001 From: Harry Date: Wed, 2 Jul 2025 14:58:44 +0800 Subject: [PATCH] feat(oauth): add support for retrieving credential info and OAuth client schema --- .../console/workspace/tool_providers.py | 42 +++++++++++++++++-- api/core/tools/builtin_tool/provider.py | 11 +++++ api/core/tools/entities/api_entities.py | 5 +++ .../tools/builtin_tools_manage_service.py | 33 +++++++++++++-- 4 files changed, 85 insertions(+), 6 deletions(-) diff --git a/api/controllers/console/workspace/tool_providers.py b/api/controllers/console/workspace/tool_providers.py index 090d5f3cee..e94fcc195f 100644 --- a/api/controllers/console/workspace/tool_providers.py +++ b/api/controllers/console/workspace/tool_providers.py @@ -376,8 +376,10 @@ class ToolBuiltinProviderCredentialsSchemaApi(Resource): user = current_user tenant_id = user.current_tenant_id - return BuiltinToolManageService.list_builtin_provider_credentials_schema( - provider, ToolProviderCredentialType.of(credential_type), tenant_id + return jsonable_encoder( + BuiltinToolManageService.list_builtin_provider_credentials_schema( + provider, ToolProviderCredentialType.of(credential_type), tenant_id + ) ) @@ -795,6 +797,33 @@ class ToolOAuthCustomClient(Resource): ) +class ToolBuiltinProviderGetOauthClientSchemaApi(Resource): + @setup_required + @login_required + @account_initialization_required + def get(self, provider): + return jsonable_encoder( + BuiltinToolManageService.get_builtin_tool_provider_oauth_client_schema( + tenant_id=current_user.current_tenant_id, provider_name=provider + ) + ) + + +class ToolBuiltinProviderGetCredentialInfoApi(Resource): + @setup_required + @login_required + @account_initialization_required + def get(self, provider): + tenant_id = current_user.current_tenant_id + + return jsonable_encoder( + BuiltinToolManageService.get_builtin_tool_provider_credential_info( + tenant_id=tenant_id, + provider=provider, + ) + ) + + # tool oauth api.add_resource(ToolPluginOAuthApi, "/oauth/plugin//tool/authorization-url") api.add_resource(ToolOAuthCallback, "/oauth/plugin//tool/callback") @@ -813,12 +842,19 @@ api.add_resource(ToolBuiltinProviderUpdateApi, "/workspaces/current/tool-provide api.add_resource( ToolBuiltinProviderSetDefaultApi, "/workspaces/current/tool-provider/builtin//default-credential" ) +api.add_resource( + ToolBuiltinProviderGetCredentialInfoApi, "/workspaces/current/tool-provider/builtin//credential/info" +) api.add_resource( ToolBuiltinProviderGetCredentialsApi, "/workspaces/current/tool-provider/builtin//credentials" ) api.add_resource( ToolBuiltinProviderCredentialsSchemaApi, - "/workspaces/current/tool-provider/builtin//credentials_schema/", + "/workspaces/current/tool-provider/builtin//credential/schema/", +) +api.add_resource( + ToolBuiltinProviderGetOauthClientSchemaApi, + "/workspaces/current/tool-provider/builtin//oauth/client-schema", ) api.add_resource(ToolBuiltinProviderIconApi, "/workspaces/current/tool-provider/builtin//icon") diff --git a/api/core/tools/builtin_tool/provider.py b/api/core/tools/builtin_tool/provider.py index 53affe9e97..ce85a37501 100644 --- a/api/core/tools/builtin_tool/provider.py +++ b/api/core/tools/builtin_tool/provider.py @@ -134,6 +134,17 @@ class BuiltinToolProviderController(ToolProviderController): """ return self.entity.oauth_schema.client_schema.copy() if self.entity.oauth_schema else [] + def get_supported_credential_types(self) -> list[str]: + """ + returns the credential support type of the provider + """ + types = [] + if self.entity.credentials_schema is not None: + types.append(ToolProviderCredentialType.API_KEY.value) + if self.entity.oauth_schema is not None: + types.append(ToolProviderCredentialType.OAUTH2.value) + return types + def get_tools(self) -> list[BuiltinTool]: """ returns a list of tools that the provider can provide diff --git a/api/core/tools/entities/api_entities.py b/api/core/tools/entities/api_entities.py index eaadd4d214..ebb503a8b3 100644 --- a/api/core/tools/entities/api_entities.py +++ b/api/core/tools/entities/api_entities.py @@ -81,3 +81,8 @@ class ToolProviderCredentialApiEntity(BaseModel): default=False, description="Whether the credential is the default credential for the provider in the workspace" ) credentials: dict = Field(description="The credentials of the provider") + + +class ToolProviderCredentialInfoApiEntity(BaseModel): + supported_credential_types: list[str] = Field(description="The supported credential types of the provider") + credentials: list[ToolProviderCredentialApiEntity] = Field(description="The credentials of the provider") \ No newline at end of file diff --git a/api/services/tools/builtin_tools_manage_service.py b/api/services/tools/builtin_tools_manage_service.py index 17c1a4b421..2abb234a83 100644 --- a/api/services/tools/builtin_tools_manage_service.py +++ b/api/services/tools/builtin_tools_manage_service.py @@ -9,12 +9,16 @@ from sqlalchemy.orm import Session from configs import dify_config from core.helper.position_helper import is_filtered from core.helper.provider_cache import NoOpProviderCredentialCache, ToolProviderCredentialsCache -from core.model_runtime.utils.encoders import jsonable_encoder from core.plugin.entities.plugin import ToolProviderID from core.plugin.impl.exc import PluginDaemonClientSideError from core.tools.builtin_tool.provider import BuiltinToolProviderController from core.tools.builtin_tool.providers._positions import BuiltinToolProviderSort -from core.tools.entities.api_entities import ToolApiEntity, ToolProviderApiEntity, ToolProviderCredentialApiEntity +from core.tools.entities.api_entities import ( + ToolApiEntity, + ToolProviderApiEntity, + ToolProviderCredentialApiEntity, + ToolProviderCredentialInfoApiEntity, +) from core.tools.entities.tool_entities import ToolProviderCredentialType from core.tools.errors import ToolNotFoundError, ToolProviderCredentialValidationError, ToolProviderNotFoundError from core.tools.tool_label_manager import ToolLabelManager @@ -31,6 +35,14 @@ logger = logging.getLogger(__name__) class BuiltinToolManageService: __MAX_BUILTIN_TOOL_PROVIDER_COUNT__ = 100 + @staticmethod + def get_builtin_tool_provider_oauth_client_schema(tenant_id: str, provider_name: str): + """ + get builtin tool provider oauth client schema + """ + provider = ToolManager.get_builtin_provider(provider_name, tenant_id) + return provider.get_oauth_client_schema() + @staticmethod def list_builtin_tool_provider_tools(tenant_id: str, provider: str) -> list[ToolApiEntity]: """ @@ -89,7 +101,7 @@ class BuiltinToolManageService: :return: the list of tool providers """ provider = ToolManager.get_builtin_provider(provider_name, tenant_id) - return jsonable_encoder(provider.get_credentials_schema_by_type(credential_type)) + return provider.get_credentials_schema_by_type(credential_type) @staticmethod def update_builtin_tool_provider( @@ -297,6 +309,21 @@ class BuiltinToolManageService: credentials.append(credential_entity) return credentials + @staticmethod + def get_builtin_tool_provider_credential_info(tenant_id: str, provider: str) -> ToolProviderCredentialInfoApiEntity: + """ + get builtin tool provider credential info + """ + provider_controller = ToolManager.get_builtin_provider(provider, tenant_id) + supported_credential_types = provider_controller.get_supported_credential_types() + credentials = BuiltinToolManageService.get_builtin_tool_provider_credentials(tenant_id, provider) + credential_info = ToolProviderCredentialInfoApiEntity( + supported_credential_types=supported_credential_types, + credentials=credentials, + ) + + return credential_info + @staticmethod def delete_builtin_tool_provider(tenant_id: str, provider: str, credential_id: str): """