From 718c2bb033c5bc6e68b1ff5f47dd20d896dee817 Mon Sep 17 00:00:00 2001
From: midego1
Date: Thu, 6 Aug 2026 06:25:17 +0000
Subject: [PATCH 1/2] Confirm before revoking a personal API key
Personal-key revoke deleted the key immediately with no confirmation,
while org-key revoke (and every other destructive action) asks first.
A personal key breaks any script or tool using it just the same, so add
the same confirmation dialog, mirroring the org-key pattern.
---
packages/react/src/pages/api-keys.tsx | 46 +++++++++++++++++++++++++--
1 file changed, 43 insertions(+), 3 deletions(-)
diff --git a/packages/react/src/pages/api-keys.tsx b/packages/react/src/pages/api-keys.tsx
index eb15084cb..b48e04856 100644
--- a/packages/react/src/pages/api-keys.tsx
+++ b/packages/react/src/pages/api-keys.tsx
@@ -233,6 +233,7 @@ export function ApiKeysPage(props: { readonly orgKeysSection?: ReactNode }) {
// stays mounted for Radix's exit animation (see CreateKeyDialogBody).
const [openCount, setOpenCount] = useState(0);
const [revokingId, setRevokingId] = useState(null);
+ const [confirmRevoke, setConfirmRevoke] = useState(null);
const handleCreate = async (name: string): Promise => {
const exit = await doCreate({ payload: { name }, reactivityKeys: apiKeyWriteKeys });
@@ -312,7 +313,11 @@ export function ApiKeysPage(props: { readonly orgKeysSection?: ReactNode }) {
) : (
-
+ setConfirmRevoke(key)}
+ />
),
})
)}
@@ -333,6 +338,42 @@ export function ApiKeysPage(props: { readonly orgKeysSection?: ReactNode }) {
/>
+
+ {/* A personal key revoke breaks any script or tool using it, so it asks
+ first — same as the org-key revoke. */}
+
);
}
@@ -492,8 +533,7 @@ function OrgApiKeysSectionBody() {
- {/* Revoking an org key breaks every backend using it, so it is the one
- revoke on this page that asks first. */}
+ {/* Revoking an org key breaks every backend using it, so it asks first. */}