From ef24b3c07db5241df0e28f5c2f54f90a5f15fdbd Mon Sep 17 00:00:00 2001 From: Philipinho <16838612+Philipinho@users.noreply.github.com> Date: Tue, 3 Mar 2026 16:07:08 +0000 Subject: [PATCH] feat: API key restriction --- .../public/locales/en-US/translation.json | 4 ++ .../components/restrict-api-to-admins.tsx | 68 +++++++++++++++++++ .../src/ee/api-key/pages/user-api-keys.tsx | 27 ++++++-- .../ee/api-key/pages/workspace-api-keys.tsx | 6 +- .../workspace/types/workspace.types.ts | 5 ++ .../workspace/services/workspace.service.ts | 3 +- apps/server/src/ee | 2 +- 7 files changed, 105 insertions(+), 10 deletions(-) create mode 100644 apps/client/src/ee/api-key/components/restrict-api-to-admins.tsx diff --git a/apps/client/public/locales/en-US/translation.json b/apps/client/public/locales/en-US/translation.json index a8cd763e..cd2b7559 100644 --- a/apps/client/public/locales/en-US/translation.json +++ b/apps/client/public/locales/en-US/translation.json @@ -604,6 +604,10 @@ "This action cannot be undone. Any applications using this API key will stop working.": "This action cannot be undone. Any applications using this API key will stop working.", "Update API key": "Update API key", "Manage API keys for all users in the workspace": "Manage API keys for all users in the workspace", + "Restrict API key creation to admins": "Restrict API key creation to admins", + "Only admins and owners can create new API keys. Existing member keys will continue to work.": "Only admins and owners can create new API keys. Existing member keys will continue to work.", + "Toggle restrict API keys to admins": "Toggle restrict API keys to admins", + "API key creation is restricted to admins by your workspace administrator.": "API key creation is restricted to admins by your workspace administrator.", "AI settings": "AI settings", "AI search": "AI search", "AI Answer": "AI Answer", diff --git a/apps/client/src/ee/api-key/components/restrict-api-to-admins.tsx b/apps/client/src/ee/api-key/components/restrict-api-to-admins.tsx new file mode 100644 index 00000000..accbc545 --- /dev/null +++ b/apps/client/src/ee/api-key/components/restrict-api-to-admins.tsx @@ -0,0 +1,68 @@ +import { Text, Switch, Tooltip } from "@mantine/core"; +import { useAtom } from "jotai"; +import { workspaceAtom } from "@/features/user/atoms/current-user-atom.ts"; +import React, { useState } from "react"; +import { useTranslation } from "react-i18next"; +import { updateWorkspace } from "@/features/workspace/services/workspace-service.ts"; +import { notifications } from "@mantine/notifications"; +import useEnterpriseAccess from "@/ee/hooks/use-enterprise-access.tsx"; +import { + ResponsiveSettingsRow, + ResponsiveSettingsContent, + ResponsiveSettingsControl, +} from "@/components/ui/responsive-settings-row"; + +export default function RestrictApiToAdmins() { + const { t } = useTranslation(); + const [workspace, setWorkspace] = useAtom(workspaceAtom); + const [checked, setChecked] = useState( + workspace?.settings?.api?.restrictToAdmins === true, + ); + const hasAccess = useEnterpriseAccess(); + + const handleChange = async (event: React.ChangeEvent) => { + const value = event.currentTarget.checked; + try { + const updatedWorkspace = await updateWorkspace({ + restrictApiToAdmins: value, + }); + setChecked(value); + setWorkspace(updatedWorkspace); + } catch (err) { + notifications.show({ + message: err?.response?.data?.message, + color: "red", + }); + } + }; + + return ( + + + + {t("Restrict API key creation to admins")} + + + {t( + "Only admins and owners can create new API keys. Existing member keys will continue to work.", + )} + + + + + + + + + + ); +} diff --git a/apps/client/src/ee/api-key/pages/user-api-keys.tsx b/apps/client/src/ee/api-key/pages/user-api-keys.tsx index b58bff7c..e4951805 100644 --- a/apps/client/src/ee/api-key/pages/user-api-keys.tsx +++ b/apps/client/src/ee/api-key/pages/user-api-keys.tsx @@ -1,5 +1,6 @@ import React, { useState } from "react"; import { Anchor, Alert, Button, Group, Space, Text } from "@mantine/core"; +import { IconInfoCircle } from "@tabler/icons-react"; import { Helmet } from "react-helmet-async"; import { useTranslation } from "react-i18next"; import SettingsTitle from "@/components/settings/settings-title"; @@ -15,6 +16,7 @@ import { useGetApiKeysQuery } from "@/ee/api-key/queries/api-key-query.ts"; import { IApiKey } from "@/ee/api-key"; import { useAtom } from "jotai"; import { workspaceAtom } from "@/features/user/atoms/current-user-atom.ts"; +import useUserRole from "@/hooks/use-user-role.tsx"; export default function UserApiKeys() { const { t } = useTranslation(); @@ -26,7 +28,10 @@ export default function UserApiKeys() { const [selectedApiKey, setSelectedApiKey] = useState(null); const { data, isLoading } = useGetApiKeysQuery({ cursor }); const [workspace] = useAtom(workspaceAtom); + const { isAdmin } = useUserRole(); const mcpEnabled = workspace?.settings?.ai?.mcp === true; + const restrictToAdmins = workspace?.settings?.api?.restrictToAdmins === true; + const canCreate = !restrictToAdmins || isAdmin; const handleCreateSuccess = (response: IApiKey) => { setCreatedApiKey(response); @@ -60,8 +65,8 @@ export default function UserApiKeys() { {t("for usage details.")} - {mcpEnabled && ( - + {mcpEnabled && canCreate && ( + }> {t( "Your workspace has MCP enabled. Use your API key to connect AI assistants.", @@ -83,11 +88,19 @@ export default function UserApiKeys() { )} - - - + {canCreate ? ( + + + + ) : restrictToAdmins ? ( + }> + + {t("API key creation is restricted to admins by your workspace administrator.")} + + + ) : null} + + +