migs
migs
Explore posts from servers
TTCTheo's Typesafe Cult
Created by migs on 1/31/2024 in #questions
TRPC Security/ Authorization Concerns
I'll edit it above, thank you!
13 replies
TTCTheo's Typesafe Cult
Created by migs on 1/31/2024 in #questions
TRPC Security/ Authorization Concerns
This was incredibly helpful, thank you so much @andersgee Inspired by this, I came up with the solution I think fits this best. Still based on cody's project so others can understand it better here's what I ended up with:
const userHasClassroomAccess = async ({
classroomId,
ctx,
}: {
classroomId: string;
ctx: {
session: Session | null;
db: PlanetScaleDatabase<typeof import("../db/schema")>;
};
}) => {
//this logic will depend a lot on your schema

const classroom = await ctx.db.query.classrooms.findFirst({
where: eq(classrooms.id, classroomId),
});

if (classroomId?.ownerId === ctx.session?.user.id) return true;

return false;
};
const userHasClassroomAccess = async ({
classroomId,
ctx,
}: {
classroomId: string;
ctx: {
session: Session | null;
db: PlanetScaleDatabase<typeof import("../db/schema")>;
};
}) => {
//this logic will depend a lot on your schema

const classroom = await ctx.db.query.classrooms.findFirst({
where: eq(classrooms.id, classroomId),
});

if (classroomId?.ownerId === ctx.session?.user.id) return true;

return false;
};
This part was what unlocked my brain mostly, I didn't know that I could easily get the input from the request here (finally read trpc documentation lol). This works perfectly for my case, since I was already sending the classroomId as input to all the procedures I needed, just like Cody is doing on the video. Note: Be careful with the input, rawInput means that it hasn't been validated with zod yet, so we validate here.
const enforceUserHasClassroomAccess = t.middleware(
async ({ ctx, next, rawInput }) => {
const { classroomId } = z.object({ classroomId: z.number() }).parse(rawInput);

if (!ctx.session?.user || !classroomId) {
throw new TRPCError({ code: "UNAUTHORIZED" });
}

const hasAccess = await userHasClassroomAccess({
classroomId: classroomId,
ctx: ctx,
});

if (!hasAccess) {
throw new TRPCError({ code: "UNAUTHORIZED" });
}

return next({
ctx: {
// infers the `session` as non-nullable
session: { ...ctx.session, user: ctx.session.user },
},
});
},
);
const enforceUserHasClassroomAccess = t.middleware(
async ({ ctx, next, rawInput }) => {
const { classroomId } = z.object({ classroomId: z.number() }).parse(rawInput);

if (!ctx.session?.user || !classroomId) {
throw new TRPCError({ code: "UNAUTHORIZED" });
}

const hasAccess = await userHasClassroomAccess({
classroomId: classroomId,
ctx: ctx,
});

if (!hasAccess) {
throw new TRPCError({ code: "UNAUTHORIZED" });
}

return next({
ctx: {
// infers the `session` as non-nullable
session: { ...ctx.session, user: ctx.session.user },
},
});
},
);
export const withClassroomAccessProcedure = t.procedure.use(
enforceUserHasClassroomAccess
);
export const withClassroomAccessProcedure = t.procedure.use(
enforceUserHasClassroomAccess
);
13 replies
TTCTheo's Typesafe Cult
Created by migs on 1/31/2024 in #questions
TRPC Security/ Authorization Concerns
Cody is in a very similar situation to mine in this video https://youtu.be/I5UXsAW9dUE?si=mGjih6SBAtJT3FNG I don't really like the way he solves this since we could always forget to add that assertion. Given this example from Cody, would it make sense to have the classroomId in the session, and change it based on the classroom you're currently managing so we could then access the classroomId in the trpc procedures ?
13 replies
TTCTheo's Typesafe Cult
Created by migs on 1/31/2024 in #questions
TRPC Security/ Authorization Concerns
That was a very good explanation. Made me realize that what I need to do, is add more data to my session object, and use that value on the calls, instead of just receiving as an input
13 replies
TTCTheo's Typesafe Cult
Created by migs on 1/31/2024 in #questions
TRPC Security/ Authorization Concerns
But also, my authorization rules will not be too complex, I was thinking of creating a table for authorizations and querying my db in the context, but not sure if this is a good thing to do
13 replies
TTCTheo's Typesafe Cult
Created by migs on 1/31/2024 in #questions
TRPC Security/ Authorization Concerns
Thanks for the suggestion, unfortunately I'm using drizzle and casl doesn't seem to have a package for drizzle, same with zenstack. Is there a good alternative for drizzle ?
13 replies