feat: jwt cache, redis health, help-ticket admin, and write rate limits
Deploy / release (push) Skipped
Deploy / deploy (push) Successful in 1m33s

Cut Auth.js DB load with cached jwtVersion checks, surface Redis in /api/health and deploy warnings, add admin help-center ticket reply UI, rate-limit API tickets/reactions/referral claims, and revoke PATs on sign-out-everywhere.

Co-authored-by: Cursor <[email protected]>
This commit is contained in:
SimoandCursor committed 2026-07-21 21:58:48 +02:00
1 parent 3bb96eb6f3
commit 968ca15c27
23 files changed
+1344 -205

No files matched your search

+76 -71
View File
@@ -4,6 +4,7 @@ import Discord from "next-auth/providers/discord";
import Google from "next-auth/providers/google";
import { env } from "@/env";
import { LaravelEncrypter } from "@/lib/auth/laravel-encrypter";
import { getCachedJwtVersion } from "@/lib/auth/jwt-version-cache";
import { checkLogin } from "@/lib/auth/password";
import { verifyTotp } from "@/lib/auth/totp";
import { prisma } from "@/lib/prisma";
@@ -210,6 +211,7 @@ export const { handlers, signIn, signOut, auth } = NextAuth({
(user as { jwtVersion?: number }).jwtVersion ??
token.jwtVersion ??
0;
token.jwtCheckedAt = Date.now();
}
if (user && account?.provider === "credentials") {
@@ -217,29 +219,58 @@ export const { handlers, signIn, signOut, auth } = NextAuth({
return token;
}
const requireLink = await siteSettings.getBool(
"oauth_require_link",
false,
);
// OAuth account linking only when establishing a session — not on
// every subsequent request (avoids siteSettings + DB on each hit).
if (user || account) {
const requireLink = await siteSettings.getBool(
"oauth_require_link",
false,
);
// Try Discord ID via SocialAccounts (always allowed, even when requireLink is true).
if (
!token.sub &&
account?.provider === "discord" &&
account.providerAccountId
) {
try {
const linked = await prisma.socialAccounts.findUnique({
where: {
provider_providerId: {
provider: "discord",
providerId: account.providerAccountId,
// Try Discord ID via SocialAccounts (always allowed, even when requireLink is true).
if (
!token.sub &&
account?.provider === "discord" &&
account.providerAccountId
) {
try {
const linked = await prisma.socialAccounts.findUnique({
where: {
provider_providerId: {
provider: "discord",
providerId: account.providerAccountId,
},
},
},
});
if (linked) {
const dbUser = await prisma.user.findUnique({
where: { id: Number(linked.userId) },
});
if (linked) {
const dbUser = await prisma.user.findUnique({
where: { id: Number(linked.userId) },
select: {
id: true,
rank: true,
username: true,
websiteJwtVersion: true,
},
});
if (dbUser) {
token.sub = String(dbUser.id);
token.rank = dbUser.rank;
token.name = dbUser.username;
token.jwtVersion = dbUser.websiteJwtVersion;
token.jwtCheckedAt = Date.now();
return token;
}
}
} catch {
// leave token as-is on lookup failure
}
}
// Email-based binding: only when requireLink is off AND account has no 2FA.
if (!requireLink && user?.email && !token.sub) {
try {
const dbUser = await prisma.user.findFirst({
where: { mail: user.email, twoFactorConfirmedAt: null },
select: {
id: true,
rank: true,
@@ -252,59 +283,33 @@ export const { handlers, signIn, signOut, auth } = NextAuth({
token.rank = dbUser.rank;
token.name = dbUser.username;
token.jwtVersion = dbUser.websiteJwtVersion;
token.jwtCheckedAt = Date.now();
}
} catch {
// leave token as-is on lookup failure
}
}
}
// Re-check jwt version at most once per minute (memory/Redis cached).
if (token.sub && !token.invalid) {
const lastCheck =
typeof token.jwtCheckedAt === "number" ? token.jwtCheckedAt : 0;
if (Date.now() - lastCheck >= 60_000) {
try {
const version = await getCachedJwtVersion(Number(token.sub));
if (
version === null ||
(token.jwtVersion ?? 0) !== version
) {
token.invalid = true;
delete token.sub;
return token;
}
token.jwtCheckedAt = Date.now();
} catch {
/* keep session on transient DB/cache errors */
}
} catch {
// leave token as-is on lookup failure
}
}
// Email-based binding: only when requireLink is off AND account has no 2FA.
if (!requireLink && user?.email && !token.sub) {
try {
const dbUser = await prisma.user.findFirst({
where: { mail: user.email, twoFactorConfirmedAt: null },
select: {
id: true,
rank: true,
username: true,
websiteJwtVersion: true,
},
});
if (dbUser) {
token.sub = String(dbUser.id);
token.rank = dbUser.rank;
token.name = dbUser.username;
token.jwtVersion = dbUser.websiteJwtVersion;
}
} catch {
// leave token as-is on lookup failure
}
}
if (token.sub && !token.invalid) {
try {
const dbUser = await prisma.user.findUnique({
where: { id: Number(token.sub) },
select: {
websiteJwtVersion: true,
rank: true,
username: true,
},
});
if (
!dbUser ||
(token.jwtVersion ?? 0) !== dbUser.websiteJwtVersion
) {
token.invalid = true;
delete token.sub;
return token;
}
token.rank = dbUser.rank;
token.name = dbUser.username;
} catch {
/* keep session on transient DB errors */
}
}