mirror of
https://github.com/eliasstepanik/core.git
synced 2026-01-11 23:28:28 +00:00
184 lines
4.6 KiB
TypeScript
184 lines
4.6 KiB
TypeScript
import {
|
|
type ActionFunctionArgs,
|
|
type LoaderFunctionArgs,
|
|
json,
|
|
} from "@remix-run/node";
|
|
import { requireAuth } from "~/utils/auth-helper";
|
|
import crypto from "crypto";
|
|
import { prisma } from "~/db.server";
|
|
|
|
// GET /api/oauth/clients - List OAuth clients for user's workspace
|
|
export const loader = async ({ request }: LoaderFunctionArgs) => {
|
|
const user = await requireAuth(request);
|
|
|
|
try {
|
|
// Get user's workspace
|
|
const userRecord = await prisma.user.findUnique({
|
|
where: { id: user.id },
|
|
include: { Workspace: true },
|
|
});
|
|
|
|
if (!userRecord?.Workspace) {
|
|
return json({ error: "No workspace found" }, { status: 404 });
|
|
}
|
|
|
|
const clients = await prisma.oAuthClient.findMany({
|
|
where: { workspaceId: userRecord.Workspace.id },
|
|
select: {
|
|
id: true,
|
|
clientId: true,
|
|
name: true,
|
|
description: true,
|
|
redirectUris: true,
|
|
allowedScopes: true,
|
|
requirePkce: true,
|
|
logoUrl: true,
|
|
homepageUrl: true,
|
|
isActive: true,
|
|
createdAt: true,
|
|
updatedAt: true,
|
|
createdBy: {
|
|
select: {
|
|
id: true,
|
|
email: true,
|
|
name: true,
|
|
},
|
|
},
|
|
},
|
|
orderBy: { createdAt: "desc" },
|
|
});
|
|
|
|
return json({ clients });
|
|
} catch (error) {
|
|
console.error("Error fetching OAuth clients:", error);
|
|
return json({ error: "Internal server error" }, { status: 500 });
|
|
}
|
|
};
|
|
|
|
// POST /api/oauth/clients - Create new OAuth client
|
|
export const action = async ({ request }: ActionFunctionArgs) => {
|
|
if (request.method !== "POST") {
|
|
return json({ error: "Method not allowed" }, { status: 405 });
|
|
}
|
|
|
|
const user = await requireAuth(request);
|
|
|
|
try {
|
|
const body = await request.json();
|
|
|
|
const {
|
|
name,
|
|
description,
|
|
redirectUris,
|
|
allowedScopes,
|
|
requirePkce,
|
|
logoUrl,
|
|
homepageUrl,
|
|
} = body;
|
|
|
|
// Validate required fields
|
|
if (!name || !redirectUris) {
|
|
return json(
|
|
{ error: "Name and redirectUris are required" },
|
|
{ status: 400 },
|
|
);
|
|
}
|
|
|
|
// Validate scopes
|
|
const validScopes = [
|
|
// Authentication scopes (Google-style)
|
|
"profile",
|
|
"email",
|
|
"openid",
|
|
// Integration scope
|
|
"integration",
|
|
"integration:read",
|
|
"integration:credentials",
|
|
"integration:manage",
|
|
"integration:webhook",
|
|
// MCP scope
|
|
"mcp",
|
|
"mcp:read",
|
|
"mcp:write",
|
|
"mcp.read",
|
|
"mcp.write",
|
|
];
|
|
|
|
const requestedScopes = Array.isArray(allowedScopes)
|
|
? allowedScopes
|
|
: [allowedScopes || "read"];
|
|
const invalidScopes = requestedScopes.filter(
|
|
(scope) => !validScopes.includes(scope),
|
|
);
|
|
|
|
if (invalidScopes.length > 0) {
|
|
return json(
|
|
{
|
|
error: `Invalid scopes: ${invalidScopes.join(", ")}. Valid scopes are: ${validScopes.join(", ")}`,
|
|
},
|
|
{ status: 400 },
|
|
);
|
|
}
|
|
|
|
// Get user's workspace
|
|
const userRecord = await prisma.user.findUnique({
|
|
where: { id: user.id },
|
|
include: { Workspace: true },
|
|
});
|
|
|
|
if (!userRecord?.Workspace) {
|
|
return json({ error: "No workspace found" }, { status: 404 });
|
|
}
|
|
|
|
if (!userRecord?.admin) {
|
|
return json({ error: "No access to create OAuth app" }, { status: 404 });
|
|
}
|
|
|
|
// Generate client credentials
|
|
const clientId = crypto.randomUUID();
|
|
const clientSecret = crypto.randomBytes(32).toString("hex");
|
|
|
|
// Create OAuth client
|
|
const client = await prisma.oAuthClient.create({
|
|
data: {
|
|
clientId,
|
|
clientSecret,
|
|
name,
|
|
description: description || null,
|
|
redirectUris: Array.isArray(redirectUris)
|
|
? redirectUris.join(",")
|
|
: redirectUris,
|
|
allowedScopes: requestedScopes.join(","),
|
|
requirePkce: requirePkce || false,
|
|
logoUrl: logoUrl || null,
|
|
homepageUrl: homepageUrl || null,
|
|
workspaceId: userRecord.Workspace.id,
|
|
createdById: user.id,
|
|
},
|
|
select: {
|
|
id: true,
|
|
clientId: true,
|
|
clientSecret: true,
|
|
name: true,
|
|
description: true,
|
|
redirectUris: true,
|
|
allowedScopes: true,
|
|
requirePkce: true,
|
|
logoUrl: true,
|
|
homepageUrl: true,
|
|
isActive: true,
|
|
createdAt: true,
|
|
},
|
|
});
|
|
|
|
return json({
|
|
success: true,
|
|
client,
|
|
message: "OAuth client created successfully",
|
|
});
|
|
} catch (error) {
|
|
console.error("Error creating OAuth client:", error);
|
|
return json({ error: "Internal server error" }, { status: 500 });
|
|
}
|
|
};
|