noed
noed
TtRPC
Created by noed on 8/27/2024 in #❓-help
Is publicProcedure safe to use with this kind of approach ?
Stack : t3stack (next 14, drizzle, pnpm) I want to expose some of my procedure with rest api for an intern old software and I want to use an API KEY approach to secure it. I have this user.ts procedure that return info of my user based on id, and this authorization.ts procedure that check if the key is valid (it's the user id for now to make some tests). Does making the user procedure public make it vulnerable if it's used like the user/[id]/route.ts file ? Is there a better way to authenticate user (use the auth cookie to make requests ?) Thanks ! (:
// user.ts
export const userRouter = createTRPCRouter({
getById: publicProcedure
.input(z.object({ id: z.string() }))
.query(async ({ ctx, input }) => {

const user = await ctx.db.query.users.findFirst({
where: (model, { eq }) => eq(model.id, input.id),
});

if (!user) {
throw new Error("User not found");
}

return user;
}),
});
// user.ts
export const userRouter = createTRPCRouter({
getById: publicProcedure
.input(z.object({ id: z.string() }))
.query(async ({ ctx, input }) => {

const user = await ctx.db.query.users.findFirst({
where: (model, { eq }) => eq(model.id, input.id),
});

if (!user) {
throw new Error("User not found");
}

return user;
}),
});
// authorization.ts
export const authorizationRouter = createTRPCRouter({
canAccess: publicProcedure
.input(z.object({ key: z.string() }))
.query(async ({ ctx, input }) => {

// TODO: Implement a real API_KEY check & update the user model to have an API_KEY field
const user = await ctx.db.query.users.findFirst({
where: (model, { eq }) => eq(model.id, input.key),
});

return user;
}),
});
// authorization.ts
export const authorizationRouter = createTRPCRouter({
canAccess: publicProcedure
.input(z.object({ key: z.string() }))
.query(async ({ ctx, input }) => {

// TODO: Implement a real API_KEY check & update the user model to have an API_KEY field
const user = await ctx.db.query.users.findFirst({
where: (model, { eq }) => eq(model.id, input.key),
});

return user;
}),
});
// user/[id]/route.ts
const userByIdHandler = async (
req: NextRequest,
{ params: { id } }: { params: { id: string } },
) => {
try {
// Check for ID
if (!id || typeof id !== "string") {
return NextResponse.json({ message: "Invalid ID" }, { status: 400 });
}

// Get the key from req header and check key
const key = req.headers.get("Authorization");
if (!key) {
return NextResponse.json({ message: "Invalid key" }, { status: 400 });
}

// Create context and caller
const ctx = await createTRPCContext({ req });
const caller = createCaller(ctx);

const access = await caller.authorization.canAccess({ key: key });

if (!access) {
return NextResponse.json({ message: "Unauthorized" }, { status: 401 });
}

const user = await caller.user.getById({ id });

return NextResponse.json(user, { status: 200 });
} catch (cause) {
if (cause instanceof TRPCError) {
// An error from tRPC occurred
const httpCode = getHTTPStatusCodeFromError(cause);
return NextResponse.json(cause, { status: httpCode });
}
// Another error occurred
console.error(cause);
return NextResponse.json(
{ message: "Internal server error" },
{ status: 500 },
);
}
};

export const GET = userByIdHandler;
// user/[id]/route.ts
const userByIdHandler = async (
req: NextRequest,
{ params: { id } }: { params: { id: string } },
) => {
try {
// Check for ID
if (!id || typeof id !== "string") {
return NextResponse.json({ message: "Invalid ID" }, { status: 400 });
}

// Get the key from req header and check key
const key = req.headers.get("Authorization");
if (!key) {
return NextResponse.json({ message: "Invalid key" }, { status: 400 });
}

// Create context and caller
const ctx = await createTRPCContext({ req });
const caller = createCaller(ctx);

const access = await caller.authorization.canAccess({ key: key });

if (!access) {
return NextResponse.json({ message: "Unauthorized" }, { status: 401 });
}

const user = await caller.user.getById({ id });

return NextResponse.json(user, { status: 200 });
} catch (cause) {
if (cause instanceof TRPCError) {
// An error from tRPC occurred
const httpCode = getHTTPStatusCodeFromError(cause);
return NextResponse.json(cause, { status: httpCode });
}
// Another error occurred
console.error(cause);
return NextResponse.json(
{ message: "Internal server error" },
{ status: 500 },
);
}
};

export const GET = userByIdHandler;
1 replies