Encountering OAuthAccountNotLinked Error on Subsequent Google Sign-Ins [Drizzle ORM]
Adapter type
@auth/drizzle-adapter
Environment
System:
OS: macOS 14.3.1
CPU: (11) arm64 Apple M3 Pro
Memory: 178.80 MB / 18.00 GB
Shell: 5.9 - /bin/zsh
Binaries:
Node: 20.11.1 - /usr/local/bin/node
npm: 10.2.4 - /usr/local/bin/npm
pnpm: 8.15.3 - /usr/local/bin/pnpm
Watchman: 2024.01.22.00 - /opt/homebrew/bin/watchman
Browsers:
Chrome: 121.0.6167.184
Edge: 121.0.2277.128
Safari: 17.3.1
npmPackages:
@auth/drizzle-adapter: ^0.7.0 => 0.7.0
next: 14.1.0 => 14.1.0
next-auth: 5.0.0-beta.11 => 5.0.0-beta.11
react: ^18.2.0 => 18.2.0
Reproduction URL
https://github.com/wpcodevo/nextauth-nextjs14-drizzle/tree/main
Describe the issue
We're experiencing an issue where users receive an OAuthAccountNotLinked error when they attempt to sign in with Google after their initial account creation and sign-out. Despite implementing allowDangerousEmailAccountLinking: true, our database shows duplicate entries in the accounts table for the same user upon a second and subsequent sign-in attempt.
The repo link uses beta-8 but it also happens with beta-11.
How to reproduce
- User signs up with Google OAuth provider.
- User signs out.
- User attempts to sign in again with the same Google account.
- The
OAuthAccountNotLinkederror occurs.
Expected behavior
The expected behavior is that a user should be able to sign in with the same Google account multiple times without encountering linking issues, assuming allowDangerousEmailAccountLinking: true is set to allow email-based account linking.
I'm hitting the same issue with Drizzle and Google. Have you tried to debug this? Like if using different database adapters solves it?
I want to dig into this so I'd be glad for any helpful observations that can help me fix it.
EDIT: I'll be using only google and I need better control over refresh tokens so I'll just roll my own solution instead.
EDIT2: actually I can still use auth.js with dangerous linking (I only support google so it's safe). Then when generating a session I just look for some account in the db that has a refresh token (only the first one has it when using google).
I'm also facing this issue using the exact same config for DrizzleAdapter (SQLite) and GoogleProvider listed here. Users can log in the first time, but after logging out, subsequent login attempts return the OAuthAccountNotLinked error when trying to sign in. To be clear, I don't want to allow dangerous email linking, I just want users to be able to sign into their single Google OAuth account, but at this point, they can't do that more than once. Is there anything I can do to fix this in the meantime? Thanks
I'm also facing this issue using the exact same config for
DrizzleAdapter(SQLite) andGoogleProviderlisted here. Users can log in the first time, but after logging out, subsequent login attempts return theOAuthAccountNotLinkederror when trying to sign in. To be clear, I don't want to allow dangerous email linking, I just want users to be able to sign into their single Google OAuth account, but at this point, they can't do that more than once. Is there anything I can do to fix this in the meantime? Thanks
Unfortunately, just allow the allowDangerousEmailAccountLinking. You can also try the workaround explained by @jankaifer in his 2nd edit.
allowDangerousEmailAccountLinking should not be necessary because you're using only the Google provider. This bug is supposed to be fixed in https://github.com/nextauthjs/next-auth/pull/10008, let us check your reproduction and get back to you. @ndom91 maybe you could help with this? 🙏
Hmm yeah i think it might be because of the providerAccountId thing we fixed recently.
Did you initially create your users in your DB with beta.8? There was a bug in how the providerAccountIds were set in that version which is fixed now.
So users logging in with beta.13 now will not match against what was saved for them originally.
More details here: https://github.com/nextauthjs/next-auth/issues/9992#issuecomment-1944062556
Long story short, if the users were created in your DB while you were using beta.7/8/9 you'll need to either:
- delete them, they'll be recreated on next login. Of course I udnerstand if thats not possible in your situation
- manually update the
account.providerAccountIdsto the correct ones (we can talk about more this if thats what you want to do) - enable the
allowDangerousEmailAccountLinkingoption
I've encountered the same issue within SvelteKit Auth using the Drizzle adapter. When signing up for the first time with either GitHub or Google, and then subsequently signing out, attempting to log in again results in an "OAuthAccountNotLinked" error.
In the DB it looks like my "account" table gets 2 records with the same email and provider
@DeveloperOskar which versions of @auth/sveltekit are you using? Are these newly created users?
It is just a side project, and yes they are newly created, then I log out and can not log back in because i get "OAuthAccountNotLinked" and see 2 accounts in the "account" table with the same email and provider.
"@auth/core": "^0.25.1",
"@auth/sveltekit": "^0.11.1",
hooks.server.js:
export const handle = sequence(
SvelteKitAuth({
providers: [
GitHub({ clientId: GITHUB_ID, clientSecret: GITHUB_SECRET }),
Google({
clientId: GOOGLE_ID,
clientSecret: GOOGLE_SECRET
})
],
pages: {
signIn: 'sign-in'
},
callbacks: {
session: ({ session, user }) => ({
...session,
user: {
...session.user,
id: user.id
}
})
},
adapter: DrizzleAdapter(db, mysqlTable)
}),
authorization
);
"@auth/core": "^0.25.1", "@auth/sveltekit": "^0.11.1",
Hey thanks for all the info.
First of all, you shouldn't need to install core as well. Simply @auth/sveltekit should do the trick. What are you using core for exactly?
Also were up to 0.13.0 of the sveltekit package, could you try that?
The setup has changed slightly, see the instructions here: https://authjs.dev/reference/sveltekit#usage
The sveltekit setup is now like the next.js one, in that you want to have a src/auth.ts which exports a few methods returned from SvelteKitAuth() including a handle method which you'd import and use in your src/hooks.server.ts.
Thanks!
Thank you @ndom91 for the help, looks like upgrading to 0.13.0 helped and using the updated instructions that you provided!
I uninstalled the CorePackage as well but I used it to get a typed type of the Account type in the "account" table
Ah gotcha, yeah those are exported from the sveltekit package now as well 👍
We wanted to avoid having people have to install both packages
Same issue here with beta15. providerAccountId from getUserByAccount keeps changing over each signin, it's not the one coming from the token sub
@jdordoigne can you provide some more details about your use-case? What version of next-auth, your config, what provider(s) are you trying to signin with and are you using a db or no, etc?
There were some previous verions where this was broken and providerAccountId was being returned as crypto.randomUUID() basically. But this should be fixed as of beta.10 or so. See packages/core/src/lib/actions/callback/oauth/callback.ts:213.
If anyone else still has an issue with this, I discovered that in my case it was because I had a custom profile() function for my provider, and this working correctly requires that the default profile handler runs.
There seem to be two separate issues in this thread.
1 Linked Accounts
I went around the loop on that issue myself, having forgotten to mark one of my providers as "safe".
I note only that the error page for this error... isn't the error page, it looks like it's probably the config.pages.signIn location with a query string etc.
I had expected my custom config.pages.error pages to be shown, with that same query string. I just wrote some code to navigate the user with this error away from config.pages.signIn to the config.pages.error.
2 Custom profiles cause multiple account table entries
If anyone else still has an issue with this, I discovered that in my case it was because I had a custom
profile()function for my provider, and this working correctly requires that the default profile handler runs.
I thought the profile callback was for the user profile (so user table), not the accounts table, but looking at it the callbacks don't seem to map 1:1 onto the database tables anyway. I can't really not have user roles, so I have to put up with multiple account table entries for a single user/ account. The difference in the entries (eg for Azure AD) is just the provider ID, but that isn't in the account callback, so I can't see how to strip it out.
Anyway, I wrote a scheduled task which runs each night and zaps all those unwanted accounts collection entries, leaving only the latest of the set. It would be nice if "provider ID", which is useless to me, could be stripped out.
It's slightly confusing that the call backs don't map onto the database collections, if you see what I mean.
I have the same issue with OAuthAccountNotLinked with Google and the Drizzle Adapter(mysql2).
[email protected] [email protected] [email protected]
Edit: I went from next-auth 4 directly to beta.19 and the user was not made in next-auth 4