auth-astro icon indicating copy to clipboard operation
auth-astro copied to clipboard

Discord provider is missing user.id in the session object

Open FurStaku opened this issue 1 year ago • 19 comments

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: '[email protected]',
    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,
		}),
	],
});

FurStaku avatar Feb 10 '24 02:02 FurStaku

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

julianfbeck avatar Feb 26 '24 19:02 julianfbeck

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;
    }
  }

julianfbeck avatar Mar 09 '24 18:03 julianfbeck

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.

FurStaku avatar Mar 10 '24 22:03 FurStaku

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;

julianfbeck avatar Mar 11 '24 09:03 julianfbeck

Plss solve this

Cocodrulo avatar Jun 25 '24 22:06 Cocodrulo

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;
    }
  }
})

willnode avatar Jun 29 '24 12:06 willnode

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

Cocodrulo avatar Jun 29 '24 14:06 Cocodrulo

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'

willnode avatar Jun 29 '24 15:06 willnode

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

image

Cocodrulo avatar Jun 30 '24 10:06 Cocodrulo

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] : '';
}

fearandesire avatar Jul 09 '24 02:07 fearandesire

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

Cocodrulo avatar Jul 09 '24 17:07 Cocodrulo

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 avatar Jul 09 '24 17:07 fearandesire

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

fearandesire avatar Jul 10 '24 01:07 fearandesire

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.

Cocodrulo avatar Jul 11 '24 14:07 Cocodrulo

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

JusticeMatthew avatar Aug 07 '24 23:08 JusticeMatthew

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

NicoToff avatar Aug 11 '24 20:08 NicoToff

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

FurStaku avatar Aug 11 '24 20:08 FurStaku

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'        
}

JusticeMatthew avatar Aug 11 '24 23:08 JusticeMatthew

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

ClyonsMT avatar Oct 02 '24 20:10 ClyonsMT

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 avatar Oct 04 '24 13:10 Cocodrulo

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

Cocodrulo avatar Oct 04 '24 13:10 Cocodrulo