Add token requirement to public TRPC endpoint to add to DB (create-t3-app)

I've created a public TRPC endpoint on the exampleRouter like so:

export const exampleRouter = createTRPCRouter({
// ... other routes
create: publicProcedure
.mutation(async ({ ctx, input }) => {
// Fetch/scrape data from somewhere
// ...

// Add to DB
const newItem = ctx.prisma.example.create({
data: {
someData: "fetched data goes here",
},
});

return newItem;
}),
});

export const exampleRouter = createTRPCRouter({
// ... other routes
create: publicProcedure
.mutation(async ({ ctx, input }) => {
// Fetch/scrape data from somewhere
// ...

// Add to DB
const newItem = ctx.prisma.example.create({
data: {
someData: "fetched data goes here",
},
});

return newItem;
}),
});
The above works if I POST to /api/trpc/example.create. I want to be able to call this from Github Actions (this part seems pretty trivial), but I don't want just anyone to be able to call the route in order to trigger it, so I thought I should add a token:

export const exampleRouter = createTRPCRouter({
// ... other routes
create: publicProcedure
.input(
z.object({
token: z.string(), // Token for authentication
})
)
.mutation(async ({ ctx, input }) => {
if (input.token !== "SECRETSAUCE") { // Use .env variable
throw new Error("Invalid token");
}
// Fetch/scrape data from somewhere
// ...

// Add to DB
const newItem = ctx.prisma.example.create({
data: {
someData: "fetched data goes here",
},
});

return newItem;
}),
});

export const exampleRouter = createTRPCRouter({
// ... other routes
create: publicProcedure
.input(
z.object({
token: z.string(), // Token for authentication
})
)
.mutation(async ({ ctx, input }) => {
if (input.token !== "SECRETSAUCE") { // Use .env variable
throw new Error("Invalid token");
}
// Fetch/scrape data from somewhere
// ...

// Add to DB
const newItem = ctx.prisma.example.create({
data: {
someData: "fetched data goes here",
},
});

return newItem;
}),
});
But I get the following error when trying to POST to the endpoint with the following body:
{
"token": "SECRETSAUCE"
}
{
"token": "SECRETSAUCE"
}
tRPC failed on example.create: [
{
"code": "invalid_type",
"expected": "object",
"received": "undefined",
"path": [],
"message": "Required"
}
]
tRPC failed on example.create: [
{
"code": "invalid_type",
"expected": "object",
"received": "undefined",
"path": [],
"message": "Required"
}
]
(Post continued in comment below)
4 Replies
epsilon42
epsilon4213mo ago
(Post continued from above) I then realised that for all I've seen so far with TRPC, the data is all within the query string, not in the body of the request. So I guess I could change the request and change it so that it's something like /api/trpc/example.create?token=SECRETSAUCE, (probably looks a bit different to this - haven't tried this yet) but I have read that this is bad practice because it exposes the token in logs etc. So my first question is: - Is it okay to add token in query string, or is there a way of extracting the data from the body of the request to validate the token sent in the body? Some other questions: - Should I be using protectedProcedure somehow or is publicProcedure the right one to use here? - Should I be avoiding TRPC altogether (the example code below seems to work when POSTing a token in the body but not sure how to add something to DB)?
// Creating a non-TRPC endpoint like below works, but not sure how to add to DB
// src/pages/api/cron-test.ts
import type { NextApiRequest, NextApiResponse } from "next";

function validateToken(token: string): boolean {
return token === "SECRETSAUCE";
}

export default function handler(req: NextApiRequest, res: NextApiResponse) {
if (req.method === "POST") {
const { token } = req.body as { token: string };

if (!token || !validateToken(token)) {
res.status(401).json({ message: "Invalid or missing token" });
return;
}

// ... Add to DB here
res.status(200).json({ message: "POST request handled with token" });
} else {
res.status(405).json({ message: "Method Not Allowed" });
}
}
// Creating a non-TRPC endpoint like below works, but not sure how to add to DB
// src/pages/api/cron-test.ts
import type { NextApiRequest, NextApiResponse } from "next";

function validateToken(token: string): boolean {
return token === "SECRETSAUCE";
}

export default function handler(req: NextApiRequest, res: NextApiResponse) {
if (req.method === "POST") {
const { token } = req.body as { token: string };

if (!token || !validateToken(token)) {
res.status(401).json({ message: "Invalid or missing token" });
return;
}

// ... Add to DB here
res.status(200).json({ message: "POST request handled with token" });
} else {
res.status(405).json({ message: "Method Not Allowed" });
}
}
There's a very real possibility that I'm approaching this the wrong way so please let me know if I should be doing something differently. I'm coming from a frontend background and quite new to backend/API stuff.
dan
dan13mo ago
If you want to call the endpoit remotely (aka not using tRPC), then its better to abstract out the trpc function into another function then use that function within the trpc endpoint and a nextjs [apps/pages]/api endpoint and use the api endpoint on github
epsilon42
epsilon4213mo ago
Is the reason you're suggesting abstracting it to another function just in the case that I want to share the same logic/functionality within tRPC? In this particular case I don't see the functionality needing to be called from within the app, only triggered externally. Does this mean I would only need to have the logic in pages/api/my-externally-called-function.ts ?
dan
dan13mo ago
Yes, using trpc for external use just complicates things and its not what it is designed for.
Want results from more Discord servers?
Add your server
More Posts
Javascript / Typescript ORMs like Drizzle or PrismaGuys sorry i know this is a very beginner question. I've been mostly a backend developer most of my VSCode Debugging - Does Client Side debugger break points work?So I've got server side debugging working in VSCode with breakpoints but I can't for the life of me Data fetching in NextJs 13.4+I have a question about this statement - In this new model, we recommend fetching data directly in tUPLOADTHING_URL is still set to localhost:3000I have my app on vercer server and I'm still getting this error: `Access to fetch at 'http://localhoSession recording tools?Hey! I want to monitor my next app, and before I look for a logging and tracking solution, I want a What is the name of the service cname.vercel-dns.com hosted on?I’m wanting to have a multi tenant app, so I need to configure my own nameserver that tenants point How to use google fonts in a T3 appLooking for recommendations for what you think is the best way to use google fonts in a T3 appCan i front a (non-prod) netlify(or other providers) app with cloudflare?Netlify has just been blocked where i live, i can't access any site with **.netlify.app Is it possibHow should we handle errors in zact? What should I return when the user is unauthorized for example?How should we handle errors in zact? What should I return when the user is unauthorized for example?WARNING: Text content did not match.../* data.ts */ ``` export const data = [...] // array of items export const randomNumGen = //Generato