Files
kan/apps/web/src/pages/api/trello/authenticate.ts
Henry 53a33c68fc feat: rate limit api routes (#336)
* feat: install rate-limiter-flexible and ioredis

* feat: setup redis client

* feat: add withRateLimit wrapper

* feat: wrap trpc endpoint in withRateLimit

* feat: wrap withRateLimit on remaining routes

* feat: exclude webhook route from rate limiting

* chore: update compose files and readme

* refactor: move into api/db packages
2026-01-25 22:28:41 +00:00

52 lines
1.5 KiB
TypeScript

import type { NextApiRequest, NextApiResponse } from "next";
import { createNextApiContext } from "@kan/api/trpc";
import { integrations } from "@kan/db/schema";
import { addYears } from "date-fns";
import { withRateLimit } from "@kan/api/utils/rateLimit";
export default withRateLimit(
{ points: 100, duration: 60 },
async (req: NextApiRequest, res: NextApiResponse) => {
if (req.method !== "POST") {
return res.status(405).json({ message: "Method not allowed" });
}
const { user } = await createNextApiContext(req);
if (!user)
return res.status(401).json({ message: "User not authenticated" });
const apiKey = process.env.TRELLO_APP_API_KEY;
if (!apiKey)
return res.status(500).json({ message: "Trello API key not set in Environment Variables" });
const token = req.body.token;
if (!token)
return res.status(400).json({ message: "No token found" });
try {
const { db } = await createNextApiContext(req);
await db.insert(integrations).values({
provider: "trello",
userId: user.id,
accessToken: token,
expiresAt: addYears(new Date(), 1),
}).onConflictDoUpdate({
set: {
accessToken: token,
expiresAt: addYears(new Date(), 1),
},
target: [integrations.userId, integrations.provider],
});
return res.status(200).json({ message: "Trello authentication successful" });
} catch (err) {
console.error("Trello authentication error:", err);
return res.status(400).json({ message: "Trello authentication failed" });
}
},
);