nextauthjs / next-auth

Authentication for the Web.
https://authjs.dev
ISC License
24.55k stars 3.45k forks source link

[BUG] `profile.email` in github provider returns null #11895

Open A91y opened 3 weeks ago

A91y commented 3 weeks ago

Provider type

GitHub

Environment

System:
    OS: Windows 11 10.0.22631
    CPU: (16) x64 AMD Ryzen 7 5800H with Radeon Graphics
    Memory: 3.44 GB / 13.86 GB
  Binaries:
    Node: 19.8.1 - D:\Program Files\nodejs\node.EXE
    Yarn: 1.22.19 - ~\AppData\Roaming\npm\yarn.CMD
    npm: 9.6.3 - D:\Program Files\nodejs\npm.CMD
    pnpm: 9.0.6 - ~\AppData\Roaming\npm\pnpm.CMD
  Browsers:
    Edge: Chromium (127.0.2651.74)
    Internet Explorer: 11.0.22621.3527
  npmPackages:
    next: 14.2.4 => 14.2.4
    next-auth: ^4.24.7 => 4.24.7
    react: ^18 => 18.3.1

Reproduction URL

https://github.com/octasol/octasol

Describe the issue

export default function Github<P extends GithubProfile>(
  options: OAuthUserConfig<P>
): OAuthConfig<P> {
  return {
    id: "github",
    name: "GitHub",
    type: "oauth",
    authorization: {
      url: "https://github.com/login/oauth/authorize",
      params: { scope: "read:user user:email" },
    },
    token: "https://github.com/login/oauth/access_token",
    userinfo: {
      url: "https://api.github.com/user",
      async request({ client, tokens }) {
        // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
        const profile = await client.userinfo(tokens.access_token!)

        if (!profile.email) {
          // If the user does not have a public email, get another via the GitHub API
          // See https://docs.github.com/en/rest/users/emails#list-public-email-addresses-for-the-authenticated-user
          const res = await fetch("https://api.github.com/user/emails", {
            headers: { Authorization: `token ${tokens.access_token}` },
          })

          if (res.ok) {
            const emails: GithubEmail[] = await res.json()
            profile.email = (emails.find((e) => e.primary) ?? emails[0]).email
          }
        }

        return profile
      },
    },
    profile(profile) {
      return {
        id: profile.id.toString(),
        name: profile.name ?? profile.login,
        email: profile.email,
        image: profile.avatar_url,
      }
    },
    style: { logo: "/github.svg", bg: "#24292f", text: "#fff" },
    options,
  }
}

profile.email always return null, even after fetching from

const res = await fetch("https://api.github.com/user/emails", {
            headers: { Authorization: `token ${tokens.access_token}` },
          })

How to reproduce

The issue can be reproduced by

import { NextAuthOptions } from "next-auth";
import GithubProvider from "next-auth/providers/github";

export const authOptions: NextAuthOptions = {
  providers: [
    GithubProvider({
      clientId: process.env.GITHUB_CLIENT_ID! as string,
      clientSecret: process.env.GITHUB_CLIENT_SECRET! as string,
    }),
  ],
  callbacks: {
    async jwt({
      token,
      account,
      profile,
    }: {
      token: any;
      account: any;
      profile?: any;
    }) {
      if (account) {
        token.accessToken = account.access_token;
      }
      if (profile) {
        token.profile = profile;
      }
      return token;
    },
    async session({ session, token }: { session: any; token: any }) {
      session.accessToken = token.accessToken;
      console.log(token.profile.email);
      session.user = { ...session.user, ...token.profile };
      return session;
    },
  },
};

Here token.profile.email return null

Expected behavior

Expected behaviour: token.profile.email should have returned with email of users

balazsorban44 commented 3 weeks ago

Per docs https://docs.github.com/en/rest/users/emails?apiVersion=2022-11-28#list-email-addresses-for-the-authenticated-user, and with us passing the user:email scope by default, this does not sound like a NextAuth.js bug. 🤔