next-auth: Keep getting redirected with error: OAuthAccountNotLinked

Describe the bug In your next-auth-example, default login screen (http://localhost:3000/api/auth/signin)

  1. I added TWITTER_ID and TWITTER_SECRET and DATABASE_URL to .env.local
  2. added all these callback URLs to twitter since they changed:
  3. did all the initial stuff: yarn && yarn add mongodb && yarn dev
  4. click sign in, then click login to twitter
  5. once it redirects back to /api/auth/callback/twitter instead of redirecting back to the home screen, it goes to /api/auth/error?error=OAuthAccountNotLinked then /api/auth/signin?error=OAuthAccountNotLinked image

I noticed that when I console.log in the signIn callback I still get the twitter data. image

Am I missing something here or is this a bug? Because I’m getting the same issue in my personal app.

Documentation feedback Documentation refers to searching through online documentation, code comments and issue history. The example project refers to next-auth-example.

  • Found the documentation helpful
  • Found documentation but was incomplete
  • Could not find relevant documentation
  • Found the example project helpful
  • Did not find the example project helpful

About this issue

  • Original URL
  • State: closed
  • Created 4 years ago
  • Reactions: 7
  • Comments: 47 (18 by maintainers)

Commits related to this issue

Most upvoted comments

I also wanted to say that I think this is a great library and I really appreciate all your hard work. 👏👏👏

please use allowDangerousEmailAccountLinking: true

https://next-auth.js.org/configuration/providers/oauth

Hi @iaincollins I just found the same error when testing oauth with Google and Github. I’m wondering is there a way to connect both providers to the same user instead of rejecting it? So sign in with Google and sign in with Github will go to the same user account.

This is the error page displayed for the OAuthAccountNotLinked:

error

If you see OAuthAccountNotLinked it means you have already signed in with a different provider that is associated with the same email address.

@nsebhastian @fzxu

Please feel free to open a new issue if you have a question about why something works a particular way.

This has come up before so I’ve raised a PR which addresses it in the FAQ:


When I sign in with another account with the same email address, why are accounts not linked automatically?

Automatic account linking on sign in is not secure between arbitrary providers - with the exception of allowing users to sign in via an email addresses as a fallback (as they must verify their email address as part of the flow).

When an email address is associated with an OAuth account it does not necessarily mean that it has been verified as belonging to account holder — how email address verification is handled is not part of the OAuth specification and varies between providers (e.g. some do not verify first, some do verify first, others return metadata indiciating the verification status).

With automatic account linking on sign in, this can be exploited by bad actors to hijack accounts by creating an OAuth account associated with the email address of another user.

For this reason it is not secure to automatically link accounts between abitrary providers on sign in, which is why this feature is generally not provided by authentication service and is not provided by NextAuth.js.

Automatic acccount linking is seen on some sites, sometimes insecurely. It can be technically possible to do automatic account linking securely if you trust all the providers involved to ensure they have securely verified the email address associated with the account, but requires placing trust (and transfering the risk) to those providers to handle the process securely.

Examples of scenarios where this is secure include with an OAuth provider you control (e.g. that only authorizes users internal to your organization) or with a provider you explicitly trust to have verified the users email address.

Automatic account linking is not a planned feature of NextAuth.js, however there is scope to improve the user experience of account linking and of handling this flow, in a secure way. Typically this involves providing a fallback option to sign in via email, which is already possible (and recommended), but the current implementation of this flow could be improved on.

Providing support for secure account linking and unlinking of additional providers - which can only be done if a user is already signed in already - was origionally a feature in v1.x but has not been present since v2.0, is planned to return in a future release.

I got this error OAuthAccountNotLinked when I had signed up with my facebook login and then trying to log in with my google account (both of them using the same email).

According to the documentation:

OAuthAccountNotLinked: If the email on the account is already linked, but not with this OAuth account

The reason for not just merging the two Oauth accounts is stated here:

[…] it is not secure to automatically link accounts between arbitrary providers on sign in, which is why this feature is generally not provided by authentication service and is not provided by NextAuth.js.

➡️ TLDR; it’s not possible to log in with more than one OAuth provider (using the same email), but it IS possible to log in with an OAuth provider AND use email login (using the same email).

For the best user experience signin page should warn the user that this user is already linked with another provider and encourage the user to either use that OAuth provider instead or log in with email. I’m still to figure out where to catch the OAuthAccountNotLinked and perform proper redirects back to signin, but I will update this post once I figure it out. 😅

please use allowDangerousEmailAccountLinking: true https://next-auth.js.org/configuration/providers/oauth

I don’t see this option as available. I am using next-auth": "^4.10.3

You should pass the allowDangerousEmailAccountLinking option to your provider, like this:

GoogleProvider({
    clientId: process.env.GOOGLE_CLIENT_ID || '',
    clientSecret: process.env.GOOGLE_CLIENT_SECRET || '',
    allowDangerousEmailAccountLinking: true,
}),

You were correct. It was the DB. Weird… So sorry I drug you through all this. I should’ve tried that from the get go.

I also tried your example with a fresh DB and it worked. Didn’t try a new collection within the same db, but I’d assume it would work with one.

please use allowDangerousEmailAccountLinking: true

https://next-auth.js.org/configuration/providers/oauth

I don’t see this option as available. I am using next-auth": "^4.10.3

I got the same error if both facebook and google has the same email. It’s better to provide option to merge user.

I’m having this issue with a new user account using email only with Auth0 (no other oauth providers are enabled), and using a brand new database isn’t a possibility. Is there an alternative to that fix?

Ah, but I only have signed in with Twitter. That’s the only Provider I have with my app besides email AND I have only used this email via twitter oauth. image

Don’t use this package fr I implemented on my own and so much easier and predictable than this trash

On Mon, 12 Feb 2024, 8:07 am Yaseen Deen, @.***> wrote:

I was having this issue as well, and in the hopes this will help at least someone: Using the Prisma adapter, I had a seeder populating the database with our administrators (users, roles, permissions, etc.) which ended up causing this. The User was being created with the default cuid() id value, instead of the (selected) provider user id.

Can you expand on this i am stuck on this issue been trying to solve for a long time now

— Reply to this email directly, view it on GitHub https://github.com/nextauthjs/next-auth/issues/519#issuecomment-1937990788, or unsubscribe https://github.com/notifications/unsubscribe-auth/AUXM4BXPBHYDJSQ57FERYV3YTF4FBAVCNFSM4PRGFAVKU5DIOJSWCZC7NNSXTN2JONZXKZKDN5WW2ZLOOQ5TCOJTG44TSMBXHA4A . You are receiving this because you commented.Message ID: @.***>

I’m getting the same error. While trying to create a user data on the database. Here’s my code:

import { getServerSession } from "next-auth";
import { PrismaAdapter } from "@next-auth/prisma-adapter";
import { prisma } from "./db";
import GoogleProvider from "next-auth/providers/google";

export const authOptions = {
  callbacks: {
    async signIn({ user, account, session }) {
      try {
        console.log(account, "account");
        console.log(user, "user");
        console.log(session, "session");
        // Check if the OAuth account is already linked to an existing user account
        const linkedAccount = await prisma.user.findUnique({
          where: {
            email: user.email,
          },
        });

        console.log(linkedAccount, "linkedAccount");

        if (linkedAccount) {
          // If the OAuth account is already linked, return the corresponding user
          return true;
        } else {
          // If the OAuth account is not linked, create a new user account and link it to the OAuth account
          const newUser = await prisma.user.create({
            data: {
              name: user.name,
              email: user.email,
              image: user.image,
              token: 0.1,
            },
          });

          // Return the newly created user
          return true;
        }
      } catch (error) {
        console.error(error);
        return false;
      }
    },
  },

  adapter: PrismaAdapter(prisma),
  secret: process.env.NEXTAUTH_SECRET,
  providers: [
    GoogleProvider({
      clientId: process.env.GOOGLE_CLIENT_ID,
      clientSecret: process.env.GOOGLE_CLIENT_SECRET,
    }),
  ],
};

export const getServerAuthSession = (ctx) => {
  return getServerSession(ctx.req, ctx.res, authOptions);
};

It works if I don’t add a callback it. But I added it because I need the token field to be added. Now I’m getting error=OAuthAccountNotLinked. if someone has resolved it can you help this fellow dev out.

Btw, I don’t have this problem in 2.2.0

I will test the example project right now and report back

added all these callback URLs to twitter since they changed: http://localhost:3000/api/auth/callback/twitter http://localhost:3000/auth/oauth/twitter/callback <- old docs said this (came up when I searched “twitter” on next-auth.js.og)

To confirm, the callback API has not changed between version 2 and version 3. The documentation for providers is correct: https://next-auth.js.org/configuration/providers#using-a-built-in-provider

The second callback URL format is for version 1 which was released in 2016-2017. At the top of the page it says “WARNING This documentation is for version 1 which is no longer supported.”

^ Edit: It might be worth us removing the v1 one docs from the website if they are coming up in search results above more relevant results.