nowaythatworked / auth-astro

Community maintained Astro integration of @auth/core
289 stars 43 forks source link

Discord provider is missing user.id in the session object #62

Open FurStaku opened 7 months ago

FurStaku commented 7 months ago

If I log the session, I only get this JSON Object back and the user.id is missing for some reason

Session Object :

{
  user: {
    name: 'staku',
    email: 'name@example.com',
    image: 'https://cdn.discordapp.com/avatars/444560731300429844/28ef1f92c9bc92f919fa2ea5182ecb16.png'
  },
  expires: '2024-03-11T01:46:51.264Z'
}

auth.config.ts :

import Discord from '@auth/core/providers/discord';

import { defineConfig } from 'auth-astro';

export default defineConfig({
    providers: [
        Discord({
            clientId: import.meta.env.DISCORD_CLIENT_ID,
            clientSecret: import.meta.env.DISCORD_CLIENT_SECRET,
        }),
    ],
});
julianfbeck commented 7 months ago

I have the same error using github. Did you find a solution?

julianfbeck commented 6 months ago

The soluzion is adding a callback inside the auth properties, thats add the userid

  ],
   callbacks: {
    session({ session, user }) {
      if (session.user) {
        session.user.id = user.id;
      }
      return session;
    }
  }
FurStaku commented 6 months ago

The soluzion is adding a callback inside the auth properties, thats add the userid

  ],
   callbacks: {
    session({ session, user }) {
      if (session.user) {
        session.user.id = user.id;
      }
      return session;
    }
  }
[auth][error] JWTSessionError: Read more at https://errors.authjs.dev#jwtsessionerror
[auth][cause]: TypeError: Cannot read properties of undefined (reading 'id')
    at Object.session (eval at instantiateModule (file:///C:/.../auth/node_modules/vite/dist/node/chunks/dep-G-px366b.js:54755:28), <anonymous>:18:31)
    at Module.session (file:///C:/.../auth/node_modules/@auth/core/lib/actions/session.js:35:52)
    at async AuthInternal (file:///C:/.../auth/node_modules/@auth/core/lib/index.js:35:24)
    at async Module.Auth (file:///C:/.../auth/node_modules/@auth/core/index.js:104:29)
    at async Module.getSession (eval at instantiateModule (file:///C:/.../auth/node_modules/vite/dist/node/chunks/dep-G-px366b.js:54755:28), <anonymous>:56:20)
    at async eval (eval at instantiateModule (file:///C:/.../auth/node_modules/vite/dist/node/chunks/dep-G-px366b.js:54755:28), <anonymous>:16:19)
    at async AstroComponentInstance.render (eval at instantiateModule (file:///C:/.../auth/node_modules/vite/dist/node/chunks/dep-G-px366b.js:54755:28), <anonymous>:44:7)    
    at async Object.render (eval at instantiateModule (file:///C:/.../auth/node_modules/vite/dist/node/chunks/dep-G-px366b.js:54755:28), <anonymous>:356:7)
    at async Module.renderChild (eval at instantiateModule (file:///C:/.../auth/node_modules/vite/dist/node/chunks/dep-G-px366b.js:54755:28), <anonymous>:36:5)
[auth][details]: {}

Doesn't work for me, I just get an error message when I try to log in, where should I add this? Adding to auth.config.ts did not work.

julianfbeck commented 6 months ago

For me i added it like this to the auth config, but i only tested it for github, not for discord. t3-stack did the same, in order to add the user.id to every object

import GitHub from '@auth/core/providers/github';
import { DrizzleAdapter } from '@auth/drizzle-adapter';

import { db } from './src/utils/db';

import type { AuthConfig } from '@auth/core';
import { env } from '@/t3-env';

export default {
  adapter: DrizzleAdapter(db),
  providers: [
    GitHub({
      clientId: env.GITHUB_CLIENT_ID,
      clientSecret: env.GITHUB_CLIENT_SECRET
    })
  ],
  callbacks: {
    session({ session, user }) {
      if (session.user) 
        session.user.id = user.id;
      }
      return session;
    }
  }
} satisfies AuthConfig;
Cocodrulo commented 3 months ago

Plss solve this

willnode commented 3 months ago

I use this to get user ID

export default defineConfig({
  providers: [
    Credentials({
         ...
    }),
  ],
  callbacks: {
    session({ session, token }) {
      if (session.user && token?.sub) {
        session.user.id = token.sub;
      }
      return session;
    }
  }
})
Cocodrulo commented 3 months ago

But that does not retrieve the actual discord ID does it? it returns a unique identificatory number but not the actual discord ID right?

willnode commented 3 months ago

I think it is.

https://github.com/nextauthjs/next-auth/blob/main/packages/core/src/providers/discord.ts#L164-L168

After reading this repo code, I came to know that 'id' is forwarded as 'token.sub'

Cocodrulo commented 3 months ago

No for what I can see. ID is now smth that not looks like the discord ID

image

fearandesire commented 2 months ago

For those struggling - the solution I used was a small function to extract it from the image URL. The numbers after /avatars has the User ID, its standard with Discord.

/**
 * @summary Extracts the Discord User ID from the `image` field
 * Custom utility function designed to enable us to get a User ID from a session (using auth-astro)
 * @param {string} imageUrl
 * @returns {string}
 */
export function extractUserIdFromImage(imageUrl: string): string {
  const match = imageUrl.match(/avatars\/(\d+)\//);
  return match ? match[1] : '';
}
Cocodrulo commented 2 months ago

And what if it has no avatar, then the image url is: 'https://cdn.discordapp.com/embed/avatars/0.png' @fearandesire

fearandesire commented 2 months ago

And what if it has no avatar, then the image url is: 'https://cdn.discordapp.com/embed/avatars/0.png' @fearandesire

Great point! I haven't come across this issue yet myself. That said, I just offered a solution that works for my needs. I'm not sure what to do in the event they don't have an avatar.

fearandesire commented 2 months ago

Following up, the solution provided by @willnode works! I explored this option for a site I recently launched, and the solution I provided prior was the cause of a silly bug as some users did not have avatars.

To clarify, for me -- this solution returns the User ID. I don't seem to get any UUID-like string as @Cocodrulo got here

Cocodrulo commented 2 months ago

I dont know why, sometimes token.sub gives the discord ID but other times it return thar strange UUID-like string. I was finally getting the discord ID and then suddenly token.sub was that kind of string again. I don't really understand.

JusticeMatthew commented 1 month ago

Any update on a fix for this issue or alternative work arounds?

I get the same issues above when using the callbacks, either user.id is not found or the token.sub is the weird UUID like value

Would love to continue using the library but I need that ID, there's really no point without it

NicoToff commented 1 month ago

For those struggling - the solution I used was a small function to extract it from the image URL. The numbers after /avatars has the User ID, its standard with Discord.

/**
 * @summary Extracts the Discord User ID from the `image` field
 * Custom utility function designed to enable us to get a User ID from a session (using auth-astro)
 * @param {string} imageUrl
 * @returns {string}
 */
export function extractUserIdFromImage(imageUrl: string): string {
  const match = imageUrl.match(/avatars\/(\d+)\//);
  return match ? match[1] : '';
}

I love this 😂 Very clever, I'm just concerned it will break if Discord randomly changes their avatar naming pattern.

Edit: And yes, as pointed out already, users with no avatar break this logic anyway

FurStaku commented 1 month ago

For those struggling - the solution I used was a small function to extract it from the image URL. The numbers after /avatars has the User ID, its standard with Discord.

/**
 * @summary Extracts the Discord User ID from the `image` field
 * Custom utility function designed to enable us to get a User ID from a session (using auth-astro)
 * @param {string} imageUrl
 * @returns {string}
 */
export function extractUserIdFromImage(imageUrl: string): string {
  const match = imageUrl.match(/avatars\/(\d+)\//);
  return match ? match[1] : '';
}

problem here is that not everyone has a profile picture, so if you don't have one, it won't work because the avatar string is empty

JusticeMatthew commented 1 month ago

All right here is my hacky solution because I don't need access to the users email

import Discord from '@auth/core/providers/discord';
import { defineConfig } from 'auth-astro';

export default defineConfig({
  providers: [
    Discord({
      clientId: import.meta.env.DISCORD_CLIENT_ID,
      clientSecret: import.meta.env.DISCORD_CLIENT_SECRET,
      async profile(profile) {
        return {
          name: profile.username,
          email: profile.id,
          image: `https://cdn.discordapp.com/avatars/${profile.id}/${profile.avatar}.png`,
        };
      },
    }),
  ],
});

gives me this from the session (verified that is my correct ID)

{
  user: {
    name: 'arknoodle',
    email: '223864942615461888',
    image: 'https://cdn.discordapp.com/avatars/223864942615461888/656ffa166759d7f24a73295a68ba023e.png'
  },
  expires: '2024-09-10T23:21:08.634Z'        
}
ClyonsMT commented 1 day ago

If I want to add guild scope, to know which servers the user is on in Discord, how do I do it?

Cocodrulo commented 6 hours ago

All right here is my hacky solution because I don't need access to the users email

import Discord from '@auth/core/providers/discord';
import { defineConfig } from 'auth-astro';

export default defineConfig({
  providers: [
    Discord({
      clientId: import.meta.env.DISCORD_CLIENT_ID,
      clientSecret: import.meta.env.DISCORD_CLIENT_SECRET,
      async profile(profile) {
        return {
          name: profile.username,
          email: profile.id,
          image: `https://cdn.discordapp.com/avatars/${profile.id}/${profile.avatar}.png`,
        };
      },
    }),
  ],
});

gives me this from the session (verified that is my correct ID)

{
  user: {
    name: 'arknoodle',
    email: '223864942615461888',
    image: 'https://cdn.discordapp.com/avatars/223864942615461888/656ffa166759d7f24a73295a68ba023e.png'
  },
  expires: '2024-09-10T23:21:08.634Z'        
}

Which version are u using?

Cocodrulo commented 6 hours ago

If I want to add guild scope, to know which servers the user is on in Discord, how do I do it?

using the discord API