Files
zopu-code/packages/backend/convex/authz.ts

43 lines
1.3 KiB
TypeScript

import { ConvexError } from "convex/values";
import type { Id } from "./_generated/dataModel";
import type { MutationCtx, QueryCtx } from "./_generated/server";
export interface AuthContext {
readonly auth: {
readonly getUserIdentity: () => Promise<{
readonly tokenIdentifier: string;
} | null>;
};
}
export const requireOwnerId = async (ctx: AuthContext): Promise<string> => {
const identity = await ctx.auth.getUserIdentity();
if (!identity) {
throw new ConvexError("Authentication required");
}
return identity.tokenIdentifier;
};
/**
* Resolve the authenticated identity and prove it is a member of the given
* organization. Throws on unauthenticated or non-member access. Returns the
* canonical user ID (the Better Auth `tokenIdentifier`).
*/
export const requireOrganizationMember = async (
ctx: QueryCtx | MutationCtx,
organizationId: Id<"organizations">
): Promise<string> => {
const userId = await requireOwnerId(ctx);
const membership = await ctx.db
.query("organizationMembers")
.withIndex("by_organizationId_and_userId", (q) =>
q.eq("organizationId", organizationId).eq("userId", userId)
)
.unique();
if (!membership) {
throw new ConvexError("Organization membership required");
}
return userId;
};