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

When using prisma adapter, user can login only one time #12456

Open
rhufsky opened this issue Jan 1, 2025 · 5 comments
Open

When using prisma adapter, user can login only one time #12456

rhufsky opened this issue Jan 1, 2025 · 5 comments
Labels
bug Something isn't working triage Unseen or unconfirmed by a maintainer yet. Provide extra information in the meantime.

Comments

@rhufsky
Copy link
Contributor

rhufsky commented Jan 1, 2025

Environment

  System:
    OS: macOS 15.1.1
    CPU: (8) arm64 Apple M1 Pro
    Memory: 75.09 MB / 16.00 GB
    Shell: 5.9 - /bin/zsh
  Binaries:
    Node: 22.12.0 - /opt/homebrew/opt/node@22/bin/node
    npm: 10.9.0 - /opt/homebrew/opt/node@22/bin/npm
    pnpm: 9.15.0 - /opt/homebrew/bin/pnpm
    bun: 1.1.40 - /opt/homebrew/bin/bun
  Browsers:
    Chrome: 131.0.6778.205
    Safari: 18.1.1
  npmPackages:
    @auth/prisma-adapter: ^2.7.4 => 2.7.4 
    next: 15.1.3 => 15.1.3 
    next-auth: ^5.0.0-beta.25 => 5.0.0-beta.25 
    react: ^19.0.0 => 19.0.0

Reproduction URL

https://github.com/rhufsky/authdemo

Describe the issue

Using a prisma adapter and gitlab Provider

  • User logs in first time, prisma adapter created records for account and user
  • User logs in for the second time, prisma adapter complains
[auth][error] OAuthAccountNotLinked: Another account already exists with the same e-mail address. Read more at https://errors.authjs.dev#oauthaccountnotlinked
    at handleLoginOrRegister (/Users/rhufsky/Documents/Development/HTL-IT/Experimental-Applications/authdemo/.next/server/chunks/e044d_@auth_core_479462._.js:2925:23)
    at async Module.callback (/Users/rhufsky/Documents/Development/HTL-IT/Experimental-Applications/authdemo/.next/server/chunks/e044d_@auth_core_479462._.js:3820:50)-

Reading https://errors.authjs.dev#oauthaccountnotlinked, we see that

For security reasons, Auth.js does not automatically link OAuth accounts to existing accounts if the user is not signed in.

While I can understand that, I also see that prisma adapter has created the user and account entries by itself, so it should allow login.

The docs also state that

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.

This is a nice solution but as far as I understand the process, this is not an option but rather a workaround that MUST be applied.

How to reproduce

Uncomment the prisma adapter entries and try to login two times.

Expected behavior

Auth.js should allow users for more that one time.

Note

I also tried the prisma adapter for MySQL, I also set allowDangerousEmailAccountLinking: true and at the second login I got

Invalid `(data)=>p.account.create()` invocation in
/..../.next/server/chunks/node_modules_d44261._.js:4245:40

  4242             id
  4243         }
  4244     }),
→ 4245 linkAccount: (data)=>p.account.create(
Unique constraint failed on the constraint: `Account_userId_key`
    at qn.handleRequestError (/Users/rhufsky/Documents/Development/HTL-IT/Docker-Applications/gitlab-manager/node_modules/@prisma/client/runtime/library.js:121:7315)
    at qn.handleAndLogRequestError (/Users/rhufsky/Documents/Development/HTL-IT/Docker-Applications/gitlab-manager/node_modules/@prisma/clien

In this case it seems that the adapter wants to create an account entry every time the user logs in ...

@rhufsky rhufsky added bug Something isn't working triage Unseen or unconfirmed by a maintainer yet. Provide extra information in the meantime. labels Jan 1, 2025
@ralphsmith80
Copy link

ralphsmith80 commented Jan 3, 2025

I'm having the same issue with drizzle and neon. I just posted this in discord.

I I've created a site using AuthJS v5 with neon and drizzle. I'm using the database session strategy.

I've created a teachable OAuth provider with works as expected. However, I can only login one time.

When I sign out and attempt to login using the same teachable OAuth provider I see this error:

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

I'm only going to be allowing the Teachable OAuth provider for login on this site. So I can add the allowDangerousEmailAccountLinking: true, option. This works to allow the sign in however, when I sign in another account is being created for the user in the account table.

This is a problem because the account table contains necessary information like the access_token and refresh_token. Since there are now multiple account rows associated to the same user for the same provider it's not possible to determine which one contains the latest access_token and refresh_token which are needed for invoking OAuth API calls against the Teachable API.

This seems like a bug, but this is the first time I've used AuthJS so I don't know if there's another expected way to handle this.

I don't have the account table constraint you've applied which allows the process to work, but I agree that there should not be multiple accounts for the same user using the same OAuth provider.

This is my Teachable Provider. It works fine with the jwt strategy and no database adapter.

import {
  TEACHABLE_AUTH_URL,
  TEACHABLE_TOKEN_URL,
  TEACHABLE_OAUTH_USER_URL,
} from '@/app/api/(teachable)/_teachable'

import type { OAuthConfig, OAuthUserConfig } from 'next-auth/providers'

export interface TeachableProfile {
  id: string
  name: string
  email: string
  role: string
  teachableRole: string
}

export default function TeachableProvider(
  config: OAuthUserConfig<TeachableProfile>
): OAuthConfig<TeachableProfile> {
  return {
    id: 'teachable',
    name: 'Teachable',
    type: 'oauth',
    // allowDangerousEmailAccountLinking: true,
    authorization: {
      url: TEACHABLE_AUTH_URL,
      params: {
        response_type: 'code',
        required_scopes: 'name:read email:read courses:read',
      },
    },
    token: TEACHABLE_TOKEN_URL,
    userinfo: TEACHABLE_OAUTH_USER_URL,
    profile(profile: TeachableProfile) {
      return {
        ...profile,
        teachableRole: profile.role,
        role: 'customer',
      }
    },
    clientId: config.clientId,
    clientSecret: config.clientSecret,
    style: {
      logo: '/images/teachable.png',
      // this doesn't work.
      // brandColor: '#f00',
    },
  }
}

@ralphsmith80
Copy link

In my case I see a new provider id for each login and that also seems wrong. @rhufsky I think you would need to remove the constraint you have to test that, but I'd be curious if you see different provider ids for Gitlab.

@ralphsmith80
Copy link

ralphsmith80 commented Jan 3, 2025

@rhufsky I think I might have it figured out. It looks like AuthJS expects an id to exist on the profile response from the OAuth provider. I was already using the profile function to add properties to the profile from Teachable. By modifying that to include an id it works without creating an additional account record.

profile(profile: TeachableProfile) {
  return {
    ...profile,
    id: profile.email,
    teachableRole: profile.role,
    role: 'customer',
  }
},

Because the email is a unique constraint for Teachable and most if not all providers, I believe this is a valid solution.

Edit:
Also confirmed this works without the need for allowDangerousEmailAccountLinking: true,. That should only be necessary if you have multiple OAuth providers, and you want to allow sign in from all of them for the same user.

@rhufsky
Copy link
Contributor Author

rhufsky commented Jan 3, 2025

I just used the existing Gitlab Provider, so maybe my problem is in the Gitlab Provider.

I did not remove the constraint but logging in the second time I get

[auth][error] OAuthAccountNotLinked: Another account already exists with the same e-mail address. 

This looks like the AuthJS tries to create a second Account entry for the same user but Auth.js's own checks forbid that.

When setting allowDangerousEmailAccountLinking: true, Authjs's checks seem to be disabled and at the second login the database complains with Unique constraint failed on the constraint: Account_userId_key, saying tat only one Account` entry may exist per user id.

I guess that the whole thing is intended to work like so:

User model
A User could have multiple accounts because of the accounts Account[] property.

Account Model
There is only one Account per User as the userID of the Account is unique.

This makes sense as User can have on Account which stores access_token and refresh_token and such.

For some reason, Auth.js tries to create a new Account entry per User at each login and I guess that is a problem.

@HousmanDigital
Copy link

HousmanDigital commented Jan 6, 2025

I encountered the same issue with Next.js 15, Auth.js 5 Beta-25, PostgreSQL (Supabase) and Prisma, where the OAuthAccountNotLinked error kept popping up. It had me stumped for days—I was convinced my code was broken.

What eventually worked for me was deleting all the tables related to the Auth system (Account, Authenticator, Sessions, User, VerificationToken) and re-pushing my schema. It seemed a bit drastic, but as soon as I did this, everything worked perfectly.

The problem appeared to be related to inconsistent data in the tables. For instance, sign-in data was populating the User table but not the Account table, leading to the error: "To confirm your identity, please sign in with the same account."

If you're facing this error, it's definitely worth a try.

Hope this helps someone.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug Something isn't working triage Unseen or unconfirmed by a maintainer yet. Provide extra information in the meantime.
Projects
None yet
Development

No branches or pull requests

3 participants