Skip to content

Instantly share code, notes, and snippets.

@ariscript
Created April 12, 2021 12:53
Show Gist options
  • Save ariscript/e0a92fb531a51c6cd81ff14ea5b15ef9 to your computer and use it in GitHub Desktop.
Save ariscript/e0a92fb531a51c6cd81ff14ea5b15ef9 to your computer and use it in GitHub Desktop.
Discord "identify guilds" NextAuth.js implementation
import NextAuth from "next-auth";
import Providers from "next-auth/providers";
export default NextAuth({
session: {
jwt: true,
},
callbacks: {
jwt: async (token, user, account, profile) => {
// adding profile items to the token
if (user) {
token.profile = profile;
token.accessToken = account.accessToken;
token.refreshToken = account.refreshToken;
}
return Promise.resolve(token);
},
// @ts-ignore
session: async (session, token) => {
// copy token information into session
// @ts-ignore
session.user.accessToken = token.accessToken;
// @ts-ignore
session.user.refreshToken = token.refreshToken;
// @ts-ignore
session.user.profile = token.profile;
// add user's guilds into session
const res = await fetch(
"https://discord.com/api/v8/users/@me/guilds",
{
// @ts-ignore
headers: { Authorization: `Bearer ${token.accessToken}` },
}
);
const data = await res.json();
// @ts-ignore
session.user.profile.guilds = data;
return session;
},
},
// configure Discord provider
providers: [
Providers.Discord({
clientId: process.env.DISCORD_ID,
clientSecret: process.env.DISCORD_SECRET,
scope: "identify guilds",
// @ts-ignore
profile(profile) {
return profile;
},
}),
],
});
@BossDaily
Copy link

BossDaily commented Nov 5, 2022

I will see if this works in 2022 with the newest next-auth

@BossDaily
Copy link

BossDaily commented Nov 6, 2022

import NextAuth from "next-auth";
import DiscordProvider from "next-auth/providers/discord";

export default NextAuth({
  session: {
    //@ts-ignore
    jwt: true,
  },
  callbacks: {
    //@ts-ignore
    jwt: async (token, user, account, profile) => {
      if (user) {
        token.profile = profile;
        token.accessToken = account.accessToken;
        token.refreshToken = account.refreshToken;
      }
      return Promise.resolve(token);
    },
    // @ts-ignore
    session: async (session, token) => {
      session.user = token.profile;
      session.accessToken = token.accessToken;
      session.refreshToken = token.refreshToken;
      const res = await fetch(`https://discord.com/api/v10/users/@me/guilds`, {
        headers: {
          Authorization: `Bearer ${token.accessToken}`,
        },
      });
      const data = await res.json();
      // @ts-ignore
      session.user.profile.guilds = data;
      return session;
    },
  },
  // Configure one or more authentication providers
  providers: [
    DiscordProvider({
      // @ts-ignore
      clientId: process.env.DISCORD_CLIENT_ID,
      // @ts-ignore
      clientSecret: process.env.DISCORD_CLIENT_SECRET,
      scope: "identify guilds email connections guilds",
      profile(profile) {
        return profile;
      },
      // ...add more providers here
    }),
  ],
});

@BossDaily
Copy link

BossDaily commented Nov 6, 2022

This is what I wrote and it doesn't work

@BossDaily
Copy link

[next-auth][error][JWT_SESSION_ERROR]
https://next-auth.js.org/errors#jwt_session_error Cannot read properties of undefined (reading 'profile') {
message: "Cannot read properties of undefined (reading 'profile')",
stack: "TypeError: Cannot read properties of undefined (reading 'profile')\n" +
' at Object.session (webpack-internal:///(api)/./pages/api/auth/[...nextauth].ts:28:34)\n' +
' at Object.session (C:\Users\BossDaily\Documents\Repos\DiscordBots\Typescript\analog-tsx\apps\dashboard\node_modules\next-auth\core\routes\session.js:56:42)\n' +
' at async NextAuthHandler (C:\Users\BossDaily\Documents\Repos\DiscordBots\Typescript\analog-tsx\apps\dashboard\node_modules\next-auth\core\index.js:158:27)\n' +
' at async NextAuthNextHandler (C:\Users\BossDaily\Documents\Repos\DiscordBots\Typescript\analog-tsx\apps\dashboard\node_modules\next-auth\next\index.js:23:19)\n' +
' at async C:\Users\BossDaily\Documents\Repos\DiscordBots\Typescript\analog-tsx\apps\dashboard\node_modules\next-auth\next\index.js:59:32\n' +
' at async Object.apiResolver (C:\Users\BossDaily\Documents\Repos\DiscordBots\Typescript\analog-tsx\apps\dashboard\node_modules\next\dist\server\api-utils\node.js:366:9)\n' +
' at async DevServer.runApi (C:\Users\BossDaily\Documents\Repos\DiscordBots\Typescript\analog-tsx\apps\dashboard\node_modules\next\dist\server\next-server.js:481:9)\n' +
' at async Object.fn (C:\Users\BossDaily\Documents\Repos\DiscordBots\Typescript\analog-tsx\apps\dashboard\node_modules\next\dist\server\next-server.js:735:37)\n' +
' at async Router.execute (C:\Users\BossDaily\Documents\Repos\DiscordBots\Typescript\analog-tsx\apps\dashboard\node_modules\next\dist\server\router.js:247:36)\n' +
' at async DevServer.run (C:\Users\BossDaily\Documents\Repos\DiscordBots\Typescript\analog-tsx\apps\dashboard\node_modules\next\dist\server\base-server.js:347:29)',
name: 'TypeError'
}

@BossDaily
Copy link

Okay here is an update, It still doesn't work but I got it to produce a different error

@BossDaily
Copy link

import NextAuth from "next-auth";
import DiscordProvider from "next-auth/providers/discord";

export default NextAuth({
  session: {
    //@ts-ignore
    jwt: true,
  },
  callbacks: {
    //@ts-ignore
    jwt: async ({ token, user, account, profile }) => {
      if (user) {
        token.profile = profile;
        token.accessToken = account?.accessToken;
        token.refreshToken = account?.refreshToken;
      }
      return Promise.resolve(token);
    },
    // @ts-ignore
    session: async ({ session, token }) => {
      // @ts-ignore
      session.accessToken = token.accessToken;
      // @ts-ignore
      session.refreshToken = token.refreshToken;
      // @ts-ignore
      session.user = token.profile;
      const res = await fetch(`https://discord.com/api/v10/users/@me/guilds`, {
        headers: {
          Authorization: `Bearer ${token.accessToken}`,
        },
      });
      const data = await res.json();
      // @ts-ignore
      session.user.profile.guilds = data;
      return session;
    },
  },
  // Configure one or more authentication providers
  providers: [
    DiscordProvider({
      // @ts-ignore
      clientId: process.env.DISCORD_CLIENT_ID,
      // @ts-ignore
      clientSecret: process.env.DISCORD_CLIENT_SECRET,
      authorization: {
        params: {
          scope: "identify guilds email connections",
        },
      },
      profile(profile) {
        return profile;
      },
      // ...add more providers here
    }),
  ],
});

@BossDaily
Copy link

[next-auth][error][JWT_SESSION_ERROR] 
  https://next-auth.js.org/errors#jwt_session_error Cannot set properties of undefined (setting 'guilds') {
    message: "Cannot set properties of undefined (setting 'guilds')",
    stack: "TypeError: Cannot set properties of undefined (setting 'guilds')\n" +
      '    at Object.session (webpack-internal:///(api)/./pages/api/auth/[...nextauth].ts:41:41)\n' +
      '    at processTicksAndRejections (node:internal/process/task_queues:96:5)\n' +
      '    at async Object.session (/home/container/projects/analog-tsx/apps/dashboard/node_modules/next-auth/core/routes/session.js:56:26)\n' +
      '    at async NextAuthHandler (/home/container/projects/analog-tsx/apps/dashboard/node_modules/next-auth/core/index.js:158:27)\n' +
      '    at async NextAuthNextHandler (/home/container/projects/analog-tsx/apps/dashboard/node_modules/next-auth/next/index.js:23:19)\n' +
      '    at async /home/container/projects/analog-tsx/apps/dashboard/node_modules/next-auth/next/index.js:59:32\n' +
      '    at async Object.apiResolver (/home/container/projects/analog-tsx/apps/dashboard/node_modules/next/dist/server/api-utils/node.js:366:9)\n' +
      '    at async DevServer.runApi (/home/container/projects/analog-tsx/apps/dashboard/node_modules/next/dist/server/next-server.js:481:9)\n' +
      '    at async Object.fn (/home/container/projects/analog-tsx/apps/dashboard/node_modules/next/dist/server/next-server.js:735:37)\n' +
      '    at async Router.execute (/home/container/projects/analog-tsx/apps/dashboard/node_modules/next/dist/server/router.js:247:36)',
    name: 'TypeError'
  }

@darrencarlin
Copy link

@BossDaily

This is what worked for me, I was able to get all the users guilds.

// [...nextauth].ts

  callbacks: {
    async jwt({ token, account, profile }) {
      if (account) {
        token.accessToken = account.access_token;
        // @ts-ignore
        token.id = profile.id;
      }
      return token;
    },
    async session({ session, token, user }) {
      // @ts-ignore
      session.accessToken = token.accessToken;
      // @ts-ignore
      session.user.id = token.id;
      return session;
    },
  },
// Next Page

export const getServerSideProps: GetServerSideProps = async (context) => {
  const session = await unstable_getServerSession(
    context.req,
    context.res,
    authOptions
  );

  if (session) {
    const guildsRes = await fetch("https://discord.com/api/users/@me/guilds", {
      headers: {
        // @ts-ignore
        Authorization: `Bearer ${session.accessToken}`,
      },
    });

    const guilds = await guildsRes.json();

    const guildOwners = guilds && guilds.filter((guild: any) => guild.owner);

    return {
      props: {
        session,
        guilds: guildOwners ,
      },
    };
  }

  return {
    redirect: {
      destination: "/",
      permanent: false,
    },
  };
};

@BossDaily
Copy link

Thanks, I got this working yesterday by doing something similar

// [...nextauth].ts
import NextAuth from "next-auth";
import DiscordProvider from "next-auth/providers/discord";

export const authOptions = {
  // Configure one or more authentication providers
  providers: [
    DiscordProvider({
      // @ts-ignore
      clientId: process.env.DISCORD_CLIENT_ID,
      // @ts-ignore
      clientSecret: process.env.DISCORD_CLIENT_SECRET,
      authorization: {
        params: {
          scope: "identify guilds email connections",
        },
      },
      profile(profile) {
        console.log(profile);
        if (profile.avatar === null) {
          const defaultAvatarNumber = parseInt(profile.discriminator) % 5;
          profile.image_url = `https://cdn.discordapp.com/embed/avatars/${defaultAvatarNumber}.png`;
        } else {
          const format = profile.avatar.startsWith("a_") ? "gif" : "png";
          profile.image_url = `https://cdn.discordapp.com/avatars/${profile.id}/${profile.avatar}.${format}`;
        }

        return {
          id: profile.id,
          name: profile.username,
          discriminator: profile.discriminator,
          image: profile.image_url,
          accentColor: profile.accentColor,
        };
      },
      // ...add more providers here
    }),
  ],
  callbacks: {
    //@ts-ignore
    jwt: async ({ token, account, profile }) => {
      if (account) {
        token.accessToken = account.access_token;
        token.tokenType = account.token_type;
      }
      if (profile) {
        token.profile = profile;
      }
      return token;
    },
    // @ts-ignore
    session: async ({ session, token }) => {
      // @ts-ignore
      session.accessToken = token.accessToken;
      // @ts-ignore
      session.refreshToken = token.refreshToken;
      // @ts-ignore
      session.tokenType = token.tokenType;
      // @ts-ignore
      session.discordUser = token.profile;
      // @ts-ignore
      
      return session;
    },
  },
};
// @ts-ignore
export default NextAuth(authOptions)
// page 
export const getServerSideProps: GetServerSideProps = async (context) => {
  const session = await unstable_getServerSession(
    context.req,
    context.res,
    authOptions
  );
  const guildFetch = await fetch(
    `https://discord.com/api/v10/users/@me/guilds`,
    {
      headers: {
        // @ts-ignore
        Authorization: `Bearer ${session?.accessToken}`,
      },
    }
  );
  const guilds = await guildFetch.json();
  
  console.log(session)
  return {
    props: {
      guilds,
    },
  };
};

@BossDaily
Copy link

BossDaily commented Nov 9, 2022

https://github.com/ana-log/analog-tsx repo im making that is a template that allows you to make discord bots with a nextjs dashboard

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment