Enhance Discord integration by adding optional bot permissions in environment files and updating the dashboard to include an "Add Bot to your Server" button. Refactor authentication logic to handle token refresh and improve error handling for Discord sessions. Update placeholder text for better clarity in the search input field.
Some checks failed
CI / Bot (Python) (push) Successful in 12s
CI / Dashboard (Next.js) (push) Failing after 8s

This commit is contained in:
TheOnlyMace
2026-07-21 22:19:13 +02:00
parent 8294c1b4f7
commit 9006b06c09
10 changed files with 229 additions and 59 deletions

View File

@@ -15,6 +15,49 @@
import DiscordProvider from "next-auth/providers/discord";
import { AuthOptions } from "next-auth";
async function refreshDiscordAccessToken(token: {
accessToken?: string;
refreshToken?: string;
expiresAt?: number;
error?: string;
[key: string]: unknown;
}) {
if (!token.refreshToken) {
return { ...token, error: "RefreshTokenMissing" as const };
}
try {
const body = new URLSearchParams({
client_id: process.env.DISCORD_CLIENT_ID || "",
client_secret: process.env.DISCORD_CLIENT_SECRET || "",
grant_type: "refresh_token",
refresh_token: String(token.refreshToken),
});
const res = await fetch("https://discord.com/api/oauth2/token", {
method: "POST",
headers: { "Content-Type": "application/x-www-form-urlencoded" },
body,
});
const data = await res.json();
if (!res.ok) {
throw data;
}
return {
...token,
accessToken: data.access_token as string,
refreshToken: (data.refresh_token as string) || token.refreshToken,
expiresAt: Math.floor(Date.now() / 1000) + Number(data.expires_in || 604800),
error: undefined,
};
} catch (error) {
console.error("Discord token refresh failed:", error);
return { ...token, error: "RefreshAccessTokenError" as const };
}
}
export const authOptions: AuthOptions = {
providers: [
DiscordProvider({
@@ -25,10 +68,28 @@ export const authOptions: AuthOptions = {
],
callbacks: {
async jwt({ token, account }) {
// Initial sign-in
if (account) {
token.accessToken = account.access_token;
return {
...token,
accessToken: account.access_token,
refreshToken: account.refresh_token,
expiresAt: account.expires_at,
};
}
return token;
const expiresAt = typeof token.expiresAt === "number" ? token.expiresAt : 0;
// Refresh ~60s before expiry
if (Date.now() < expiresAt * 1000 - 60_000) {
return token;
}
return refreshDiscordAccessToken(token as {
accessToken?: string;
refreshToken?: string;
expiresAt?: number;
error?: string;
});
},
async session({ session, token }) {
if (session.user) {
@@ -36,6 +97,8 @@ export const authOptions: AuthOptions = {
session.user.id = token.sub;
// @ts-ignore
session.accessToken = token.accessToken;
// @ts-ignore
session.error = token.error;
}
return session;
},