import Link from "next/link"; import { ShieldCheck } from "lucide-react"; import { getWorkspace } from "@/lib/session"; import { listApiKeys } from "@/lib/queries/account"; import { PageHeader } from "@/components/ui/page-header"; import { Alert } from "@/components/ui/alert"; import { cn } from "@/lib/utils"; import { KeysTable } from "@/components/dashboard/api-keys/keys-table"; import { CreateKeyDialog } from "@/components/dashboard/api-keys/create-key-dialog"; export const dynamic = "force-dynamic"; export const metadata = { title: "API keys · Fetcha" }; export default async function ApiKeysPage({ searchParams }: { searchParams: Promise<{ project?: string; new?: string }> }) { const sp = await searchParams; const ws = await getWorkspace(); // ?project=all → every project of the org; ?project= → that project; default → current project. const allProjects = sp.project === "all"; const requested = !allProjects && sp.project ? ws.projects.find((p) => p.id === sp.project) : null; const scopeProject = allProjects ? null : requested ?? ws.project; const keys = await listApiKeys(ws.organization.id, scopeProject?.id ?? null); const projectOptions = ws.projects.map((p) => ({ id: p.id, name: p.name, environment: p.environment })); const active = keys.filter((k) => k.status === "active").length; return (
} />

{active} active · {keys.length - active} inactive

Auth docs } >
  • Keys are hashed at rest — we cannot recover a lost secret, only rotate it.
  • Rotate regularly and give every service, environment and contractor its own key with the minimum scopes.
  • Never commit keys to source control or ship them in browser code. Load them from environment variables on your server.
); } function FilterLink({ href, active, children }: { href: string; active: boolean; children: React.ReactNode }) { return ( {children} ); }