Skip to content

Commit 37cfdc3

Browse files
authored
Merge pull request #1828 from dubinc/restrict-token-update
Restrict token update to owners only
2 parents e52e9c0 + dfb1b02 commit 37cfdc3

File tree

5 files changed

+38
-28
lines changed

5 files changed

+38
-28
lines changed

apps/web/app/app.dub.co/(dashboard)/[slug]/settings/tokens/page-client.tsx

Lines changed: 22 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
"use client";
22

3+
import { clientAccessCheck } from "@/lib/api/tokens/permissions";
34
import { scopesToName } from "@/lib/api/tokens/scopes";
45
import useWorkspace from "@/lib/swr/use-workspace";
56
import { TokenProps } from "@/lib/types";
@@ -27,7 +28,7 @@ import { useState } from "react";
2728
import useSWR from "swr";
2829

2930
export default function TokensPageClient() {
30-
const { id: workspaceId } = useWorkspace();
31+
const { id: workspaceId, role } = useWorkspace();
3132
const { pagination, setPagination } = usePagination();
3233
const [createdToken, setCreatedToken] = useState<string | null>(null);
3334
const [selectedToken, setSelectedToken] = useState<TokenProps | null>(null);
@@ -61,6 +62,12 @@ export default function TokensPageClient() {
6162
setSelectedToken,
6263
});
6364

65+
const accessCheckError = clientAccessCheck({
66+
action: "tokens.write",
67+
role,
68+
customPermissionDescription: "update or delete API keys",
69+
}).error;
70+
6471
const { table, ...tableProps } = useTable({
6572
data: tokens || [],
6673
loading: isLoading && !error && !tokens,
@@ -151,10 +158,12 @@ export default function TokensPageClient() {
151158
rowCount: tokens?.length || 0,
152159
thClassName: "border-l-0",
153160
tdClassName: "border-l-0",
154-
onRowClick: (row) => {
155-
setSelectedToken(row.original);
156-
setShowAddEditTokenModal(true);
157-
},
161+
onRowClick: accessCheckError
162+
? undefined
163+
: (row) => {
164+
setSelectedToken(row.original);
165+
setShowAddEditTokenModal(true);
166+
},
158167
emptyState: (
159168
<AnimatedEmptyState
160169
title="No tokens found"
@@ -224,6 +233,7 @@ function RowMenuButton({
224233
}) {
225234
const [isOpen, setIsOpen] = useState(false);
226235

236+
const { role } = useWorkspace();
227237
const { DeleteTokenModal, setShowDeleteTokenModal } = useDeleteTokenModal({
228238
token,
229239
});
@@ -258,6 +268,13 @@ function RowMenuButton({
258268
className="h-8 whitespace-nowrap px-2"
259269
variant="outline"
260270
icon={<Dots className="h-4 w-4 shrink-0" />}
271+
disabledTooltip={
272+
clientAccessCheck({
273+
action: "tokens.write",
274+
role,
275+
customPermissionDescription: "update or delete API keys",
276+
}).error
277+
}
261278
/>
262279
</Popover>
263280
</>

apps/web/lib/api/rbac/permissions.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -86,7 +86,7 @@ export const ROLE_PERMISSIONS: {
8686
{
8787
action: "tokens.write",
8888
description: "create, update, or delete API keys",
89-
roles: ["owner", "member"],
89+
roles: ["owner"],
9090
},
9191
{
9292
action: "oauth_apps.read",

apps/web/lib/api/tokens/scopes.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,15 +3,15 @@ import { PermissionAction } from "../rbac/permissions";
33
import { ResourceKey } from "../rbac/resources";
44

55
export const SCOPES = [
6-
"workspaces.read",
7-
"workspaces.write",
86
"links.read",
97
"links.write",
108
"tags.read",
119
"tags.write",
1210
"analytics.read",
1311
"domains.read",
1412
"domains.write",
13+
"workspaces.read",
14+
"workspaces.write",
1515
"conversions.write",
1616
"apis.all", // All API scopes
1717
"apis.read", // All read scopes

apps/web/ui/modals/add-edit-token-modal.tsx

Lines changed: 11 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
import { ResourceKey, RESOURCES } from "@/lib/api/rbac/resources";
2+
import { clientAccessCheck } from "@/lib/api/tokens/permissions";
23
import {
34
getScopesByResourceForRole,
45
Scope,
@@ -124,6 +125,7 @@ function AddEditTokenModal({
124125
onTokenCreated?.(result.token);
125126
}
126127
} else {
128+
setSaving(false);
127129
toast.error(result.error.message);
128130
}
129131
};
@@ -140,24 +142,6 @@ function AddEditTokenModal({
140142
[role, conversionEnabled],
141143
);
142144

143-
const helpTexts = {
144-
user: {
145-
title:
146-
"This API key will be tied to your user account – if you are removed from the workspace, it will be deleted.",
147-
cta: "Learn more",
148-
href: "https://dub.co/docs/api-reference/tokens",
149-
},
150-
machine: {
151-
title: isOwner
152-
? "A new bot member will be added to your workspace, and the key will be associated with it. Since the key is not tied to your account, it will not be deleted even if you leave the workspace."
153-
: "Only the workspace owner can create machine users.",
154-
cta: "Learn more",
155-
href: "https://dub.co/docs/api-reference/tokens#machine-users",
156-
},
157-
};
158-
159-
const helpText = helpTexts[data.isMachine ? "machine" : "user"];
160-
161145
return (
162146
<>
163147
<Modal
@@ -362,11 +346,20 @@ function AddTokenButton({
362346
setShowAddEditTokenModal: Dispatch<SetStateAction<boolean>>;
363347
buttonProps?: Partial<ButtonProps>;
364348
}) {
349+
const { role } = useWorkspace();
350+
365351
return (
366352
<div>
367353
<Button
368354
text="Create API key"
369355
onClick={() => setShowAddEditTokenModal(true)}
356+
disabledTooltip={
357+
clientAccessCheck({
358+
action: "tokens.write",
359+
role,
360+
customPermissionDescription: "create new API keys",
361+
}).error || undefined
362+
}
370363
{...buttonProps}
371364
/>
372365
</div>

apps/web/ui/modals/delete-token-modal.tsx

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -113,8 +113,8 @@ function DeleteTokenModal({
113113
mutate(endpoint.mutate);
114114
setShowDeleteTokenModal(false);
115115
} else {
116-
const error = await res.text();
117-
toast.error(error);
116+
const { error } = await res.json();
117+
toast.error(error.message);
118118
}
119119
});
120120
}}

0 commit comments

Comments
 (0)