Skip to content

Commit d8d9835

Browse files
committed
refactor(webapp): unify admin api route auth via shared helper
Replaces duplicated inline PAT + admin checks across 24 admin api routes with the shared requireAdminApiRequest helper. Refactors platform-notifications.ts to compose the generic authenticateAdminRequest with neverthrow instead of duplicating the PAT + admin check.
1 parent c3619bf commit d8d9835

25 files changed

+57
-524
lines changed

apps/webapp/app/routes/admin.api.v1.environments.$environmentId.engine.repair-queues.ts

Lines changed: 2 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ import { ActionFunctionArgs, json } from "@remix-run/server-runtime";
22
import pMap from "p-map";
33
import { z } from "zod";
44
import { $replica, prisma } from "~/db.server";
5-
import { authenticateApiRequestWithPersonalAccessToken } from "~/services/personalAccessToken.server";
5+
import { requireAdminApiRequest } from "~/services/personalAccessToken.server";
66
import { determineEngineVersion } from "~/v3/engineVersion.server";
77
import { engine } from "~/v3/runEngine.server";
88

@@ -16,26 +16,7 @@ const BodySchema = z.object({
1616
});
1717

1818
export async function action({ request, params }: ActionFunctionArgs) {
19-
// Next authenticate the request
20-
const authenticationResult = await authenticateApiRequestWithPersonalAccessToken(request);
21-
22-
if (!authenticationResult) {
23-
return json({ error: "Invalid or Missing API key" }, { status: 401 });
24-
}
25-
26-
const user = await prisma.user.findUnique({
27-
where: {
28-
id: authenticationResult.userId,
29-
},
30-
});
31-
32-
if (!user) {
33-
return json({ error: "Invalid or Missing API key" }, { status: 401 });
34-
}
35-
36-
if (!user.admin) {
37-
return json({ error: "You must be an admin to perform this action" }, { status: 403 });
38-
}
19+
await requireAdminApiRequest(request);
3920

4021
const parsedParams = ParamsSchema.parse(params);
4122

apps/webapp/app/routes/admin.api.v1.environments.$environmentId.engine.report.ts

Lines changed: 2 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
import { json, LoaderFunctionArgs } from "@remix-run/server-runtime";
22
import { z } from "zod";
33
import { $replica, prisma } from "~/db.server";
4-
import { authenticateApiRequestWithPersonalAccessToken } from "~/services/personalAccessToken.server";
4+
import { requireAdminApiRequest } from "~/services/personalAccessToken.server";
55
import { determineEngineVersion } from "~/v3/engineVersion.server";
66
import { engine } from "~/v3/runEngine.server";
77

@@ -16,26 +16,7 @@ const SearchParamsSchema = z.object({
1616
});
1717

1818
export async function loader({ request, params }: LoaderFunctionArgs) {
19-
// Next authenticate the request
20-
const authenticationResult = await authenticateApiRequestWithPersonalAccessToken(request);
21-
22-
if (!authenticationResult) {
23-
return json({ error: "Invalid or Missing API key" }, { status: 401 });
24-
}
25-
26-
const user = await prisma.user.findUnique({
27-
where: {
28-
id: authenticationResult.userId,
29-
},
30-
});
31-
32-
if (!user) {
33-
return json({ error: "Invalid or Missing API key" }, { status: 401 });
34-
}
35-
36-
if (!user.admin) {
37-
return json({ error: "You must be an admin to perform this action" }, { status: 403 });
38-
}
19+
await requireAdminApiRequest(request);
3920

4021
const parsedParams = ParamsSchema.parse(params);
4122

apps/webapp/app/routes/admin.api.v1.environments.$environmentId.schedules.recover.ts

Lines changed: 2 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -1,34 +1,15 @@
11
import { ActionFunctionArgs, json, LoaderFunctionArgs } from "@remix-run/server-runtime";
22
import { z } from "zod";
33
import { prisma } from "~/db.server";
4-
import { authenticateApiRequestWithPersonalAccessToken } from "~/services/personalAccessToken.server";
4+
import { requireAdminApiRequest } from "~/services/personalAccessToken.server";
55
import { scheduleEngine } from "~/v3/scheduleEngine.server";
66

77
const ParamsSchema = z.object({
88
environmentId: z.string(),
99
});
1010

1111
export async function action({ request, params }: ActionFunctionArgs) {
12-
// Next authenticate the request
13-
const authenticationResult = await authenticateApiRequestWithPersonalAccessToken(request);
14-
15-
if (!authenticationResult) {
16-
return json({ error: "Invalid or Missing API key" }, { status: 401 });
17-
}
18-
19-
const user = await prisma.user.findUnique({
20-
where: {
21-
id: authenticationResult.userId,
22-
},
23-
});
24-
25-
if (!user) {
26-
return json({ error: "Invalid or Missing API key" }, { status: 401 });
27-
}
28-
29-
if (!user.admin) {
30-
return json({ error: "You must be an admin to perform this action" }, { status: 403 });
31-
}
12+
await requireAdminApiRequest(request);
3213

3314
const parsedParams = ParamsSchema.parse(params);
3415

apps/webapp/app/routes/admin.api.v1.environments.$environmentId.ts

Lines changed: 3 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
import { ActionFunctionArgs, json, LoaderFunctionArgs } from "@remix-run/server-runtime";
22
import { z } from "zod";
33
import { prisma } from "~/db.server";
4-
import { authenticateApiRequestWithPersonalAccessToken } from "~/services/personalAccessToken.server";
4+
import { requireAdminApiRequest } from "~/services/personalAccessToken.server";
55
import { engine } from "~/v3/runEngine.server";
66
import { updateEnvConcurrencyLimits } from "~/v3/runQueue.server";
77

@@ -15,26 +15,7 @@ const RequestBodySchema = z.object({
1515
});
1616

1717
export async function action({ request, params }: ActionFunctionArgs) {
18-
// Next authenticate the request
19-
const authenticationResult = await authenticateApiRequestWithPersonalAccessToken(request);
20-
21-
if (!authenticationResult) {
22-
return json({ error: "Invalid or Missing API key" }, { status: 401 });
23-
}
24-
25-
const user = await prisma.user.findUnique({
26-
where: {
27-
id: authenticationResult.userId,
28-
},
29-
});
30-
31-
if (!user) {
32-
return json({ error: "Invalid or Missing API key" }, { status: 401 });
33-
}
34-
35-
if (!user.admin) {
36-
return json({ error: "You must be an admin to perform this action" }, { status: 403 });
37-
}
18+
await requireAdminApiRequest(request);
3819

3920
const parsedParams = ParamsSchema.parse(params);
4021

@@ -71,26 +52,7 @@ const SearchParamsSchema = z.object({
7152
});
7253

7354
export async function loader({ request, params }: LoaderFunctionArgs) {
74-
// Next authenticate the request
75-
const authenticationResult = await authenticateApiRequestWithPersonalAccessToken(request);
76-
77-
if (!authenticationResult) {
78-
return json({ error: "Invalid or Missing API key" }, { status: 401 });
79-
}
80-
81-
const user = await prisma.user.findUnique({
82-
where: {
83-
id: authenticationResult.userId,
84-
},
85-
});
86-
87-
if (!user) {
88-
return json({ error: "Invalid or Missing API key" }, { status: 401 });
89-
}
90-
91-
if (!user.admin) {
92-
return json({ error: "You must be an admin to get this endpoint" }, { status: 403 });
93-
}
55+
await requireAdminApiRequest(request);
9456

9557
const parsedParams = ParamsSchema.parse(params);
9658

apps/webapp/app/routes/admin.api.v1.feature-flags.ts

Lines changed: 2 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -1,30 +1,11 @@
11
import { ActionFunctionArgs, json } from "@remix-run/server-runtime";
22
import { prisma } from "~/db.server";
3-
import { authenticateApiRequestWithPersonalAccessToken } from "~/services/personalAccessToken.server";
3+
import { requireAdminApiRequest } from "~/services/personalAccessToken.server";
44
import { makeSetMultipleFlags } from "~/v3/featureFlags.server";
55
import { validatePartialFeatureFlags } from "~/v3/featureFlags";
66

77
export async function action({ request }: ActionFunctionArgs) {
8-
// Next authenticate the request
9-
const authenticationResult = await authenticateApiRequestWithPersonalAccessToken(request);
10-
11-
if (!authenticationResult) {
12-
return json({ error: "Invalid or Missing API key" }, { status: 401 });
13-
}
14-
15-
const user = await prisma.user.findFirst({
16-
where: {
17-
id: authenticationResult.userId,
18-
},
19-
});
20-
21-
if (!user) {
22-
return json({ error: "Invalid or Missing API key" }, { status: 401 });
23-
}
24-
25-
if (!user.admin) {
26-
return json({ error: "You must be an admin to perform this action" }, { status: 403 });
27-
}
8+
await requireAdminApiRequest(request);
289

2910
try {
3011
// Parse the request body

apps/webapp/app/routes/admin.api.v1.gc.ts

Lines changed: 2 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,7 @@ import { type DataFunctionArgs } from "@remix-run/node";
22
import { PerformanceObserver } from "node:perf_hooks";
33
import { runInNewContext } from "node:vm";
44
import v8 from "v8";
5-
import { prisma } from "~/db.server";
6-
import { authenticateApiRequestWithPersonalAccessToken } from "~/services/personalAccessToken.server";
5+
import { requireAdminApiRequest } from "~/services/personalAccessToken.server";
76

87
async function waitTillGcFinishes() {
98
let resolver: (value: PerformanceEntry) => void;
@@ -36,21 +35,7 @@ async function waitTillGcFinishes() {
3635
}
3736

3837
export async function loader({ request }: DataFunctionArgs) {
39-
const authenticationResult = await authenticateApiRequestWithPersonalAccessToken(request);
40-
41-
if (!authenticationResult) {
42-
throw new Response("You must be an admin to perform this action", { status: 403 });
43-
}
44-
45-
const user = await prisma.user.findFirst({
46-
where: {
47-
id: authenticationResult.userId,
48-
},
49-
});
50-
51-
if (!user?.admin) {
52-
throw new Response("You must be an admin to perform this action", { status: 403 });
53-
}
38+
await requireAdminApiRequest(request);
5439

5540
const entry = await waitTillGcFinishes();
5641

apps/webapp/app/routes/admin.api.v1.llm-models.$modelId.ts

Lines changed: 3 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -1,24 +1,10 @@
11
import { type ActionFunctionArgs, type LoaderFunctionArgs, json } from "@remix-run/server-runtime";
22
import { z } from "zod";
33
import { prisma } from "~/db.server";
4-
import { authenticateApiRequestWithPersonalAccessToken } from "~/services/personalAccessToken.server";
5-
6-
async function requireAdmin(request: Request) {
7-
const authResult = await authenticateApiRequestWithPersonalAccessToken(request);
8-
if (!authResult) {
9-
throw json({ error: "Invalid or Missing API key" }, { status: 401 });
10-
}
11-
12-
const user = await prisma.user.findUnique({ where: { id: authResult.userId } });
13-
if (!user?.admin) {
14-
throw json({ error: "You must be an admin to perform this action" }, { status: 403 });
15-
}
16-
17-
return user;
18-
}
4+
import { requireAdminApiRequest } from "~/services/personalAccessToken.server";
195

206
export async function loader({ request, params }: LoaderFunctionArgs) {
21-
await requireAdmin(request);
7+
await requireAdminApiRequest(request);
228

239
const model = await prisma.llmModel.findUnique({
2410
where: { id: params.modelId },
@@ -69,7 +55,7 @@ const UpdateModelSchema = z.object({
6955
});
7056

7157
export async function action({ request, params }: ActionFunctionArgs) {
72-
await requireAdmin(request);
58+
await requireAdminApiRequest(request);
7359

7460
const modelId = params.modelId!;
7561

apps/webapp/app/routes/admin.api.v1.llm-models.missing.ts

Lines changed: 2 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -1,24 +1,9 @@
11
import { type LoaderFunctionArgs, json } from "@remix-run/server-runtime";
2-
import { prisma } from "~/db.server";
3-
import { authenticateApiRequestWithPersonalAccessToken } from "~/services/personalAccessToken.server";
2+
import { requireAdminApiRequest } from "~/services/personalAccessToken.server";
43
import { getMissingLlmModels } from "~/services/admin/missingLlmModels.server";
54

6-
async function requireAdmin(request: Request) {
7-
const authResult = await authenticateApiRequestWithPersonalAccessToken(request);
8-
if (!authResult) {
9-
throw json({ error: "Invalid or Missing API key" }, { status: 401 });
10-
}
11-
12-
const user = await prisma.user.findUnique({ where: { id: authResult.userId } });
13-
if (!user?.admin) {
14-
throw json({ error: "You must be an admin to perform this action" }, { status: 403 });
15-
}
16-
17-
return user;
18-
}
19-
205
export async function loader({ request }: LoaderFunctionArgs) {
21-
await requireAdmin(request);
6+
await requireAdminApiRequest(request);
227

238
const url = new URL(request.url);
249
const lookbackHours = parseInt(url.searchParams.get("lookbackHours") ?? "24", 10);

apps/webapp/app/routes/admin.api.v1.llm-models.reload.ts

Lines changed: 2 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,18 +1,9 @@
11
import { type ActionFunctionArgs, json } from "@remix-run/server-runtime";
2-
import { prisma } from "~/db.server";
3-
import { authenticateApiRequestWithPersonalAccessToken } from "~/services/personalAccessToken.server";
2+
import { requireAdminApiRequest } from "~/services/personalAccessToken.server";
43
import { llmPricingRegistry } from "~/v3/llmPricingRegistry.server";
54

65
export async function action({ request }: ActionFunctionArgs) {
7-
const authResult = await authenticateApiRequestWithPersonalAccessToken(request);
8-
if (!authResult) {
9-
return json({ error: "Invalid or Missing API key" }, { status: 401 });
10-
}
11-
12-
const user = await prisma.user.findUnique({ where: { id: authResult.userId } });
13-
if (!user?.admin) {
14-
return json({ error: "You must be an admin to perform this action" }, { status: 403 });
15-
}
6+
await requireAdminApiRequest(request);
167

178
if (!llmPricingRegistry) {
189
return json({ error: "LLM cost tracking is disabled" }, { status: 400 });

apps/webapp/app/routes/admin.api.v1.llm-models.seed.ts

Lines changed: 2 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,19 +1,11 @@
11
import { type ActionFunctionArgs, json } from "@remix-run/server-runtime";
22
import { seedLlmPricing, syncLlmCatalog } from "@internal/llm-model-catalog";
33
import { prisma } from "~/db.server";
4-
import { authenticateApiRequestWithPersonalAccessToken } from "~/services/personalAccessToken.server";
4+
import { requireAdminApiRequest } from "~/services/personalAccessToken.server";
55
import { llmPricingRegistry } from "~/v3/llmPricingRegistry.server";
66

77
export async function action({ request }: ActionFunctionArgs) {
8-
const authResult = await authenticateApiRequestWithPersonalAccessToken(request);
9-
if (!authResult) {
10-
return json({ error: "Invalid or Missing API key" }, { status: 401 });
11-
}
12-
13-
const user = await prisma.user.findUnique({ where: { id: authResult.userId } });
14-
if (!user?.admin) {
15-
return json({ error: "You must be an admin to perform this action" }, { status: 403 });
16-
}
8+
await requireAdminApiRequest(request);
179

1810
const url = new URL(request.url);
1911
const action = url.searchParams.get("action") ?? "seed";

0 commit comments

Comments
 (0)