Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Auth0] OAuthAccountNotLinked: Another account already exists with the same e-mail address #9992

Closed
pippinmole opened this issue Feb 11, 2024 · 22 comments · Fixed by #10008
Closed
Assignees
Labels
bug Something isn't working providers

Comments

@pippinmole
Copy link

pippinmole commented Feb 11, 2024

Provider type

Auth0

Environment

System:
OS: Windows 11 10.0.22631
CPU: (16) x64 AMD Ryzen 7 5700X 8-Core Processor
Memory: 9.76 GB / 31.93 GB
Binaries:
Node: 20.9.0 - C:\Program Files\nodejs\node.EXE
Yarn: 1.22.19 - ~\AppData\Roaming\npm\yarn.CMD
npm: 10.2.4 - C:\Program Files\nodejs\npm.CMD
pnpm: 8.11.0 - C:\Program Files\nodejs\pnpm.CMD
Browsers:
Edge: Chromium (121.0.2277.112)
Internet Explorer: 11.0.22621.1
npmPackages:
@auth/prisma-adapter: ^1.3.3 => 1.3.3
next: latest => 14.1.0
next-auth: beta => 5.0.0-beta.9
react: ^18.2.0 => 18.2.0

Reproduction URL

https://github.com/pippinmole/auth0-authjs-bug

Describe the issue

I haev a default setup with a prisma schema defined here, authjs config defined here,

  1. Log in using some custom credentials (this will insert a user into the database)
  2. Log out
  3. Log back in using the same credentials
  4. Observe server logs

Please see attached video

Recording.2024-02-11.001449.mp4

As the error message says, I've taken a look at this, and this is what it suggests:

If you trust the OAuth provider to have verified the user's email address, you can enable automatic account linking by setting allowDangerousEmailAccountLinking: true in the provider configuration.

I shouldn't have to enable a dangerous flag just so a user can log in twice

Additional note: Everything works perfectly with the default GitHub provider, so it looks like it's specific to the provider

How to reproduce

  1. Clone repo
  2. Copy .env.example to .env
  3. Enter relevant .env file variables for auth0
  4. yarn run dev
  5. Log in as the video above shows

Expected behavior

It should let you log in the second time with no issues

@pippinmole pippinmole added bug Something isn't working providers triage Unseen or unconfirmed by a maintainer yet. Provide extra information in the meantime. labels Feb 11, 2024
@AdytZZa22
Copy link

Same issue here with Github & Google provider. If I delete the session manually from the browser & try to login back, I get the same error: OAuthAccountNotLinked: Another account already exists with the same e-mail address

@jbultez
Copy link

jbultez commented Feb 11, 2024

Hello,

Same issue here on "next-auth": "^5.0.0-beta.9" with the google provider.

[auth][error] OAuthAccountNotLinked: Another account already exists with the same e-mail address .Read more at https://errors.authjs.dev#oauthaccountnotlinked

@Dailton-Bastos
Copy link

Same issue here with "^5.0.0-beta.9", but "^5.0.0-beta.4" was working.

@nnad3N
Copy link

nnad3N commented Feb 12, 2024

I did some quick tests on vercel and versions beta.7 and beta.8 gave the same error as beta.9. The error occurs with the google provider, github one is working. Works fine with beta.5.

@ThangHuuVu ThangHuuVu removed the triage Unseen or unconfirmed by a maintainer yet. Provide extra information in the meantime. label Feb 12, 2024
@ThangHuuVu
Copy link
Member

we're tracking this issue, thanks for reporting!
@ndom91 it looks like #9932 didn't fix the issue entirely - seems like OIDC providers still have some issue.

@ndom91
Copy link
Member

ndom91 commented Feb 14, 2024

Thanks for your patience everyone, this should be fixed in 5.0.0-beta.11. Please let us know if yuo're still having any issues with it 🙏

@pippinmole
Copy link
Author

pippinmole commented Feb 14, 2024

Hi @ndom91,

As I sat at my desk I got the email that this was merged, perfect timing. Unfortunately, it looks like I still get the same issue. Please see the attached video.

Recording.2024-02-14.144757.mp4

I'll run through what I'm doing in the video

  1. npx prisma migrate reset - this resets the database by deleting everything in the database and applying migrations (no user entried in database)
  2. Start the dev server
  3. Log in through Auth0 (it has my Auth0 account cached, but is using the email as shown in the user dropdown menu)
  4. Log out
  5. Log in through GitHub (same email)
  6. Observe error in server logs

This is using the latest beta version 5.0.0-beta.11 as shown at the start of the video. This code can be found in the repro linked in the opening message of this issue. Here it is to save some time.

Let me know if you need any more information.

Edit
As a side note, at the end of the video I see some logs (which I assume are left from your testing), which print the contents of headers. Nothing big but worth removing?

@ndom91
Copy link
Member

ndom91 commented Feb 14, 2024

@pippinmole hey thanks for the quick response!

So just some quick notes, non-OIDC providers (Like Github) were fixed in beta.9 already. This latest PR was just applying the same fix to OIDC providers (like Auth0 and Google).

So I just double checked with 5.0.0-beta.5 and created a user with Google (OIDC provider). I then upgraded to 5.0.0-beta.11 and tried to login with that same user.

Where it would previously throw the "oauth account already exists" error, I was now able to successfully login.

In addition, I couldn't see any of the logging you pointed out with the published beta.11 version.

It looks like yuo're tryign this with our app/exmaples/nextjs application. Is that right? I'm happy to help get to the bottom of this. Did you make any changes to the auth.ts file that's currently in main there?

EDIT: Ah just noticed you posted a link to a repo, let me take a look 👀

@ndom91
Copy link
Member

ndom91 commented Feb 14, 2024

@pippinmole Just thought of something.. Regarding that database of users in your demo app, when was the Github user created? The one that yuo're trying to login with but triggers the error? Do you happen to remember which version of next-auth you were using?

@pippinmole
Copy link
Author

Do you happen to remember which version of next-auth you were using?

If you're referring to the video in the opening comment, then the versions were as such (from my yarn.lock file):

"@auth/[email protected]":
next-auth@beta: version "5.0.0-beta.9"

If you need the full repro, this is the commit before upgrading to beta 11: https://github.com/pippinmole/auth0-authjs-bug/tree/638200d60c57a6e6ca15168538d1ed73717f97d0

@pippinmole
Copy link
Author

pippinmole commented Feb 14, 2024

@ndom91 So in the first video it shows a bug where you can log in the first time with Auth0, then logging in the second time with the SAME PROVIDER causes that error, and the recent video I sent shows me logging in first time with Auth0, then trying to log in via GitHub (THROUGH AUTH0) and getting the error, because of the same email address conflict

Edit
Please let me know if I'm getting this confused. Should user linkage work such that a user can log into one provider (lets say GitHub) with email A, log out, and then be able to log in to another provider (lets say Auth0), with email A (same email)?

@pippinmole
Copy link
Author

Where it would previously throw the "oauth account already exists" error, I was now able to successfully login.

I think I've confused myself here. Here's a video (doing exactly the same thing as the first video), but it working successfully on the latest version (beta 11):

Recording.2024-02-14.152358.mp4

So it looks like the original issue is fixed.

@ndom91
Copy link
Member

ndom91 commented Feb 14, 2024

@pippinmole okay I'm pretty sure I know what the issue is.. The root bug in this GH issue should be fixed, howeverrr if you created the users in your DB during beta.6,7,8,9 that were available for the last 3-4 days you'll run into an error signing in with them now.

The issue boils down to the fact that your account.providerAccountId field for your GitHub user wasn't correctly set during those versions.

The easiest thing to do is to just drop the account + user rows from your DB, next time you login with them they will be recreated with the correct values. However, I know that might not be possible in a production environment. If that's not an option for you, you can manually modify the account.providerAccountId to match the (correct) one that's used to match now.

For Github, yuor providerAccountId can easily be found by visiting https://github.com/pippinmole.png and grabbing the ID in the URL that it redirects you to. So in your case, it redirects to https://avatars.githubusercontent.com/u/40035529?v=4 making your Github providerAccountId=40035529.

So what you want to do is set the account.providerAccountId = 40035529 for your Github user in your DB. With prisma you can run pnpm exec prisma studio to open a nice little DB editing UI.

Some general notes on your repository:

  • You don't need to explicitly install / import anything from @auth/core. If you've got next-auth, you can import all of the provdiers from there as well, i.e. import GitHub from "next-auth/providers/github".
  • Also the providers now auto-detect environment variables if they're named in the expected fashion, as you're seemingly doing (i.e. AUTH_GITHUB_ID/AUTH_GITHUB_SECRET). So you can just do provider: [Auth0, Github].

@ndom91
Copy link
Member

ndom91 commented Feb 14, 2024

Ah okay, good to hear. Did you create a new DB / users?

@pippinmole
Copy link
Author

Yes, at the start I ran npx prisma migrate reset which clears the database.

@pippinmole
Copy link
Author

pippinmole commented Feb 14, 2024

So just to confirm the intended behaviour, if I do the following:

  1. Clear the database via npx prisma migrate reset
  2. Log in with GitHub (which creates a user entry with email [email protected]
  3. Log out
  4. Log in with Auth0 using the same email ([email protected])

Should it either:
a) Link my Auth0 account as if I logged in via GitHub
b) Give me the following error message: OAuthAccountNotLinked: Another account already exists with the same e-mail address .Read more at https://errors.authjs.dev#oauthaccountnotlinked

@ndom91
Copy link
Member

ndom91 commented Feb 14, 2024

Yeah so this logging in with one provider and then another provider with the same email is a different topic. You can read more about it here and here (see second item under "Security"). We call it "Account linking".

But long story short, you can enable this with the provider config option allowDangerousEmailAccountLinking: true

@pippinmole
Copy link
Author

Perfect, thank you for your help with all of this

@jbultez
Copy link

jbultez commented Feb 14, 2024

Hello,

@ndom91 I tried your fix on version 5.0.11 and it solved the problem concerning authentication with Google. (thanks for it)

However I don't know if it has anything to do with this update but now the redirect after a connection with credentials doesn't work anymore.

It may be my fault for changing the configuration, but here are the logs

Error: NEXT_REDIRECT
    at getRedirectError (webpack-internal:///(action-browser)/./node_modules/next/dist/client/components/redirect.js:49:19)
    at redirect (webpack-internal:///(action-browser)/./node_modules/next/dist/client/components/redirect.js:60:11)
    at signIn (webpack-internal:///(action-browser)/./node_modules/next-auth/lib/actions.js:63:89)
    at async login (webpack-internal:///(action-browser)/./actions/users/login.ts:28:9)
    at async /my-app/node_modules/next/dist/compiled/next-server/app-page.runtime.dev.js:39:406
    at async t0 (/my-app/node_modules/next/dist/compiled/next-server/app-page.runtime.dev.js:38:5773)
    at async rh (/my-app/node_modules/next/dist/compiled/next-server/app-page.runtime.dev.js:39:23636)
    at async doRender (/my-app/node_modules/next/dist/server/base-server.js:1391:30)
    at async cacheEntry.responseCache.get.routeKind (/my-app/node_modules/next/dist/server/base-server.js:1552:28)
    at async DevServer.renderToResponseWithComponentsImpl (/my-app/node_modules/next/dist/server/base-server.js:1460:28)
    at async DevServer.renderPageComponent (/my-app/node_modules/next/dist/server/base-server.js:1843:24)
    at async DevServer.renderToResponseImpl (/my-app/node_modules/next/dist/server/base-server.js:1881:32)
    at async DevServer.pipeImpl (/my-app/node_modules/next/dist/server/base-server.js:909:25)
    at async NextNodeServer.handleCatchallRenderRequest (/my-app/node_modules/next/dist/server/next-server.js:266:17)
    at async DevServer.handleRequestImpl (/my-app/node_modules/next/dist/server/base-server.js:805:17) {
  digest: 'NEXT_REDIRECT;replace;http://localhost:3000/settings;303;',
  mutableCookies: p {
    _parsed: Map(6) {
      'next-auth.csrf-token' => [Object],
      'next-auth.callback-url' => [Object],
      'next-auth.session-token' => [Object],
      'authjs.csrf-token' => [Object],
      'authjs.callback-url' => [Object],
      'authjs.session-token' => [Object]
    },
    _headers: HeadersList {
      cookies: [Array],
      [Symbol(headers map)]: [Map],
      [Symbol(headers map sorted)]: null
    }
  }
}

@ndom91
Copy link
Member

ndom91 commented Feb 15, 2024

@jbultez I can't reproduce with [email protected] directly. I am able to login with the credentials provider and jwt session (no database) like normal.

Can you provide me some more details about your setup? A reproduction URL from stackblitz.com or similar would be great.

@jbultez
Copy link

jbultez commented Feb 15, 2024

Hello @ndom91

I've managed to correct my problem, but I still don't understand how this error could occur.

I have a server action where I use the next-auth signIn. Here is the code

"use server";
import * as z from "zod";
import { userLoginSchema } from "@/schemas/user.schema";
import { signIn } from "@/auth";
import { DEFAULT_LOGIN_REDIRECT } from "@/routes";
import { AuthError } from "next-auth";

export const login = async (values: z.infer<typeof userLoginSchema>) => {
  const validateFields = userLoginSchema.safeParse(values);

  if (!validateFields.success) {
    return { error: "Invalid data provided" };
  }

  const { email, password } = validateFields.data;

  try {
    await signIn("credentials", {
      email,
      password,
      redirectTo: DEFAULT_LOGIN_REDIRECT,
    });
  } catch (error) {
    // I see in my server console the error message
    console.log(error);
    if (error instanceof AuthError) {
      switch (error.type) {
        case "CredentialsSignin":
          return { error: "Invalid email or password" };
        default:
          return { error: "Something went wrong" };
      }
    }
    // If I let the return error The NEXTREDIRECT error is there
    return { error: "Something went wrong" };
    // If I put `throw error` the NEXTREDIRECT error is gone and my user is logged in and redirected nicely
    // throw error;
  }
  return { success: "You are now logged in" };
};

If I use throw error until return {error: "Something went wrong"} all is fine.

@vehktaur
Copy link

Problem: NextAuth.js Creates New Accounts on Every Login (GitHub and Google)

Root Cause: Missing providerAccountId in Profile Callback

The issue arises from how NextAuth.js generates the providerAccountId. This value is used to match users with existing accounts. By default, it is derived from the id returned in the profile callback of the OAuth provider (e.g., GitHub, Google). However, since the profile callback wasn't returning an id, NextAuth.js generated a new providerAccountId with each sign-in, causing it to treat the sign-in as a new account.

Solution: Ensure id is Returned in Profile Callback

I was already modifying the profile callback for customizing user creation in the database. However, I wasn't including the id property, assuming MongoDB would generate it automatically. But the profile callback needs to return an id, which NextAuth.js uses to correctly match the user to an existing account.

To fix this, I updated the profile callback for both GitHub and Google to return a consistent id. Now, NextAuth.js uses this id as the providerAccountId, ensuring the user is matched correctly with their existing account on subsequent sign-ins.

Here’s how I customized the profile callbacks for both providers:

GitHub Provider:

const githubProvider = GitHub({
  profile: (profile: GitHubProfile) => {
    const name = profile.name?.split(' ');
    return {
      id: profile.id.toString(),  // Ensure the 'id' is returned
      firstName: name?.[0] ?? 'unknown',
      lastName: name?.[1],
      email: profile.email,
      image: profile.avatar_url,
      username: profile.login,
    };
  },
});

export default githubProvider;

Google Provider:

const googleProvider = Google({
  profile: (profile: GoogleProfile) => {
      id: profile.sub,  // Ensure the 'id' (sub) is returned
      firstName: profile.given_name,
      lastName: profile.family_name,
      email: profile.email,
      image: profile.picture,
      username: `${profile.given_name}${profile.family_name}`.toLowerCase() ?? 'unknown',
  },
});

export default googleProvider;

Explanation:

  • GitHub returns the user’s id in the OAuth response, so I made sure to include it in the profile callback as id: profile.id.toString().
  • Google returns a sub (subject) field, which I used as the id in the profile callback (id: profile.sub).

Outcome:

With these changes, the providerAccountId is consistently returned and properly stored, ensuring that NextAuth.js can now correctly match users with their accounts on subsequent logins. No more duplicate accounts are created, and everything works as expected.

Conclusion:

Make sure the profile callback in your OAuth providers returns an id. This ensures that the providerAccountId used by NextAuth.js is consistent and unique, solving issues with duplicate accounts and incorrect sign-ins.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug Something isn't working providers
Projects
None yet
Development

Successfully merging a pull request may close this issue.

8 participants