45 lines
1.4 KiB
TypeScript
45 lines
1.4 KiB
TypeScript
import { NextResponse } from "next/server";
|
|
import { getSessionUser, canMutate } from "@/lib/session";
|
|
import { getOrgMembers } from "@/lib/team";
|
|
import { safeError } from "@/lib/errors";
|
|
|
|
/**
|
|
* GET /api/team
|
|
*
|
|
* Returns the joined members-with-roles view for the caller's org.
|
|
* Gated on `canMutate` — only owners and platform users can see the
|
|
* full member list. A `user`-role member shouldn't be browsing the
|
|
* roster.
|
|
*
|
|
* Platform admins viewing this endpoint see members of their OWN
|
|
* platform org. To inspect customer org membership cross-cut, use
|
|
* ZITADEL Console — that's the deliberate boundary between portal
|
|
* (customer self-service) and console (full IAM).
|
|
*/
|
|
export async function GET() {
|
|
const user = await getSessionUser();
|
|
if (!user) {
|
|
return NextResponse.json({ error: "Unauthorized" }, { status: 401 });
|
|
}
|
|
if (!canMutate(user)) {
|
|
return NextResponse.json({ error: "Forbidden" }, { status: 403 });
|
|
}
|
|
if (user.isPersonal) {
|
|
return NextResponse.json(
|
|
{ error: "Personal accounts do not have a team." },
|
|
{ status: 403 }
|
|
);
|
|
}
|
|
|
|
try {
|
|
const members = await getOrgMembers(user.orgId);
|
|
return NextResponse.json({ members });
|
|
} catch (e: any) {
|
|
console.error("Failed to list team members:", e);
|
|
return NextResponse.json(
|
|
{ error: safeError(e, "Failed to list team members") },
|
|
{ status: 500 }
|
|
);
|
|
}
|
|
}
|