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.
This commit is contained in:
@@ -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;
|
||||
},
|
||||
|
||||
Reference in New Issue
Block a user