How to resolve 'getUserByAccount is not a function' in next-auth? - next.js

I've updated Nextjs to it's newest version and also updated next-auth and the prisma adapter as specified by the docs.
However, when I try to authenticate in the app with signIn I get the following error with the latest updates:
[next-auth][error][OAUTH_CALLBACK_HANDLER_ERROR]
https://next-auth.js.org/errors#oauth_callback_handler_error getUserByAccount is not a function {
message: 'getUserByAccount is not a function',
stack: 'TypeError: getUserByAccount is not a function\n' +
' at Object.callback (/home/.../node_modules/next-auth/core/routes/callback.js:81:39)\n' +
' at runMicrotasks (<anonymous>)\n' +
' at processTicksAndRejections (internal/process/task_queues.js:95:5)\n' +
' at async NextAuthHandler (/home/.../node_modules/next-auth/core/index.js:103:28)\n' +
' at async NextAuthNextHandler (/home/.../node_modules/next-auth/next/index.js:40:7)\n' +
' at async [...]/node_modules/next-auth/next/index.js:80:32\n' +
' at async Object.apiResolver (/home/.../node_modules/next/dist/server/api-utils.js:102:9)\n' +
' at async DevServer.handleApiRequest (/home/.../node_modules/next/dist/server/next-server.js:1014:9)\n' +
' at async Object.fn (/home/.../node_modules/next/dist/server/next-server.js:901:37)\n' +
' at async Router.execute (/home/.../node_modules/next/dist/server/router.js:210:32)',
name: 'TypeError'
}
Is there something I'm doing wrong, or is there an incompatibility I'm missing?
Relevant package.json:
...
"#next-auth/prisma-adapter": "^0.5.2-next.19",
"next": "^12.0.3",
"next-auth": "4.0.0-beta.6",
"prisma": "^3.4.1",
...
[...nextauth].ts:
import NextAuth from 'next-auth';
import CognitoProvider from 'next-auth/providers/cognito';
import { PrismaAdapter } from '#next-auth/prisma-adapter';
import { PrismaClient } from '#prisma/client';
const prisma = new PrismaClient();
export default NextAuth({
adapter: PrismaAdapter(prisma),
providers: [
CognitoProvider({
clientId: process.env.COGNITO_CLIENT_ID,
clientSecret: process.env.COGNITO_CLIENT_SECRET,
issuer: process.env.COGNITO_ISSUER,
}),
],
callbacks: {
async session({ session, user }) {
session.userId = user.id;
session.role = user.role;
return Promise.resolve(session);
},
},
});

Finally resolved the problem. Since next-auth has moved to monorepo, updating package was not enough, you need to uninstall it first then install it again.
Run:
npm uninstall next-auth #next-auth/prisma-adapter
then:
npm install #next-auth/prisma-adapter
This fixed it for me.

In the NextAuth.JS 4.0 the "Prisma schema" have slightly changed.
From the upgrade guide:
created_at/createdAt and updated_at/updatedAt fields are removed from all Models.
user_id/userId consistently named userId.
compound_id/compoundId is removed from Account.
access_token/accessToken is removed from Session.
email_verified/emailVerified on User is consistently named email_verified.
provider_id/providerId renamed to provider on Account
provider_type/providerType renamed to type on Account
provider_account_id/providerAccountId on Account is consistently named providerAccountId
access_token_expires/accessTokenExpires on Account renamed to expires_in
New fields on Account: expires_at, token_type, scope, id_token, session_state
verification_requests table has been renamed to verification_tokens
Complete new schema in:
https://next-auth.js.org/adapters/prisma

Related

next-auth: Why occurs 'OAuthCallback' error only in production?

I want add signin features using 'GoogleProvider' in next-auth.
I finished google cloud and firebase settings
OAuth 2.0 client ID in Credentials
App domain, Authorized domains in OAuth consent screen
create web app in firebase project settings
and [...nextauth].ts code is below:
import NextAuth, { NextAuthOptions } from "next-auth";
import GoogleProvider from "next-auth/providers/google";
import KakaoProvider from "next-auth/providers/kakao"
import { FirestoreAdapter } from "#next-auth/firebase-adapter";
import { db } from "../../../firebase.config";
const authOptions: NextAuthOptions = {
providers: [
GoogleProvider({
clientId: process.env.GOOGLE_CLIENT_ID_DEV as string,
clientSecret: process.env.GOOGLE_CLIENT_SECRET_DEV as string
})
],
secret: process.env.NEXTAUTH_SECRET,
session: {
strategy: "jwt",
maxAge: 3 * 60 * 60
},
adapter: FirestoreAdapter(db.app.options),
pages: {
signIn: '/login'
},
callbacks: {
async session({ session, user, token }) {
return session;
}
},
debug: true
}
export default NextAuth(authOptions);
This project is deploying with Github Actions, Cloud Run, Firebase Hosting.
It works very well in local but not works in production.
Interestingly, It works well in Cloud Run project service URL.
Only not works in domain web page that used Firebase Hosting.
so, I tried these
change Authorized redirect URIs in OAuth 2.0 client ID
Edit app registration in OAuth consent screen
callbackUrl property in signIn function
Is this problem caused by Firebase Hosting?
How can I solve this problem?
Thanks.
+add
When I was looking log in Cloud Run, I found these logs:
https://next-auth.js.org/errors#oauth_callback_error checks.state argument is missing.
error: TypeError: checks.state argument is missing.
name: 'OAuthCallbackError'

What is the best practice to bypass my specific dynamic code evaluation in next.js middleware?

I use next.js middleware to retrieve a data stored inside a cookie, and to check in a db (using strapi) if this specific user exists, or if he needs to register before going further.
// middleware.js
import { getToken } from 'next-auth/jwt';
import qs from 'qs';
import { MY_DB } from './constants';
export async function middleware(request) {
const token = await getToken({
req: request,
secret: process.env.SECRET,
});
const params = qs.stringify({
filters: {
address: {
$eq: token.sub,
},
},
});
const url = MY_DB + '/api/users/?' + params;
const result = await fetch(url, {
method: 'GET',
headers: { accept: 'application/json' },
});
// remaining code checks if the request is empty or not and returns the appropriate page
(...)
building my project returns the following error :
Failed to compile.
./node_modules/.pnpm/function-bind#1.1.1/node_modules/function-bind/implementation.js
Dynamic Code Evaluation (e. g. 'eval', 'new Function', 'WebAssembly.compile') not allowed in Edge Runtime
Learn More: https://nextjs.org/docs/messages/edge-dynamic-code-evaluation
Import trace for requested module:
./node_modules/.pnpm/function-bind#1.1.1/node_modules/function-bind/implementation.js
./node_modules/.pnpm/function-bind#1.1.1/node_modules/function-bind/index.js
./node_modules/.pnpm/get-intrinsic#1.1.3/node_modules/get-intrinsic/index.js
./node_modules/.pnpm/side-channel#1.0.4/node_modules/side-channel/index.js
./node_modules/.pnpm/qs#6.11.0/node_modules/qs/lib/stringify.js
./node_modules/.pnpm/qs#6.11.0/node_modules/qs/lib/index.js
> Build failed because of webpack errors
 ELIFECYCLE  Command failed with exit code 1.
I highly suspect the qs.stringify call given the stacktrace, but how can I overcome this in an elegant way ?

pdf.getDocument does not throw a PasswordException

Using react web app
package.json
"react": "^16.10.2",
"react-pdf": "^5.7.2",
imports:
import {pdfjs} from "react-pdf";
pdfjs.GlobalWorkerOptions.workerSrc = `//unpkg.com/pdfjs-dist#${pdfjs.version}/build/pdf.worker.min.js`;
When loading encrypted (protected) pdf file, promise does not throw a PasswordException as it should
code
const data = convertDataURIToBinary(base64PdfData); //implementation not important
pdfjs.getDocument({data, password: ''}).promise.then(doc => {
console.warn('ends up here even with wrong password!')
}).catch(e => {
console.error('never executed, why?')
})
imported pdfjs dependency is version 2.12.313 so API should match

Next js - Next Auth - Keep having error=OAuthCreateAccount (google provider)

I have set up next-auth with the GoogleProvider.
Everything works fine locally, however in production, I am having aOAuthCreateAccount error: api/auth/signin?error=OAuthCreateAccount
stating "Try signing in with a different account."
I have provided the ID & Secret of the Provider, I have dropped my DB, tried to log with multiples accounts... I do not understand. Is there something that my production environment is not accessing?
Here's my nextauth.js:
`
import NextAuth from "next-auth";
import GoogleProvider from "next-auth/providers/google";
import CredentialsProvider from "next-auth/providers/credentials";
import { MongoDBAdapter } from "#next-auth/mongodb-adapter";
import clientPromise from "../../../lib/mongodb";
export default NextAuth({
providers: [
GoogleProvider({
clientId: process.env.GOOGLE_CLIENT_ID,
clientSecret: process.env.GOOGLE_CLIENT_SECRET,
}),
// ...add more providers here
],
secret: process.env.NEXTAUTH_SECRET,
// Can custom page & path
pages: {
signOut: "/auth/signout",
error: "/auth/error", // Error code passed in query string as ?error=
verifyRequest: "/auth/verify-request", // (used for check email message)
// newUser: "/auth/new-user", // New users will be directed here on first sign in (leave the property out if not of interest)
newUser: "/recruiter/2", // New users will be directed here on first sign in (leave the property out if not of interest)
},
adapter: MongoDBAdapter(clientPromise),
});
`
And my mongodb.js:
`
import { MongoClient } from "mongodb";
const uri = process.env.MONGODB_URI;
const options = {
useUnifiedTopology: true,
useNewUrlParser: true,
};
let client;
let clientPromise;
if (!process.env.MONGODB_URI) {
throw new Error("Please add your Mongo URI to .env.local");
}
if (process.env.NODE_ENV === "development") {
// In development mode, use a global variable so that the value
// is preserved across module reloads caused by HMR (Hot Module Replacement).
if (!global._mongoClientPromise) {
client = new MongoClient(uri, options);
global._mongoClientPromise = client.connect();
}
clientPromise = global._mongoClientPromise;
} else {
// In production mode, it's best to not use a global variable.
client = new MongoClient(uri, options);
clientPromise = client.connect();
}
// Export a module-scoped MongoClient promise. By doing this in a
// separate module, the client can be shared across functions.
export default clientPromise;
`
Thank you!
Read the documentations.
Look on Stackoverflow and github thread, tried all the offered solutions, in vain.
I have managed to fix it reading this thorough article: https://medium.com/geekculture/why-and-how-to-get-started-with-next-auth-61740558b45b
I was missing the database variable in my deployment system (vercel) :)

MissingSecret [MissingSecretError]: Please define a `secret` in production

According to the docs https://next-auth.js.org/configuration/options#secret ,
adding a NEXTAUTH_SECRET as an environment variable, you don't have to define this option.
But in vercel production I still get,
2022-03-24T10:37:19.571Z 710a4b4b-24d3-4fb4-b991-9eb44179efc8 ERROR [next-auth][error][NO_SECRET]
https://next-auth.js.org/errors#no_secret Please define a `secret` in production. MissingSecret [MissingSecretError]: Please define a `secret` in production.
at assertConfig (/var/task/node_modules/next-auth/core/lib/assert.js:24:14)
at NextAuthHandler (/var/task/node_modules/next-auth/core/index.js:34:52)
at NextAuthNextHandler (/var/task/node_modules/next-auth/next/index.js:16:51)
at /var/task/node_modules/next-auth/next/index.js:52:38
at Object.apiResolver (/var/task/node_modules/next/dist/server/api-utils/node.js:182:15)
at processTicksAndRejections (internal/process/task_queues.js:95:5)
at async NextNodeServer.runApi (/var/task/node_modules/next/dist/server/next-server.js:386:9)
at async Object.fn (/var/task/node_modules/next/dist/server/base-server.js:488:37)
at async Router.execute (/var/task/node_modules/next/dist/server/router.js:228:32)
at async NextNodeServer.run (/var/task/node_modules/next/dist/server/base-server.js:600:29) {
code: 'NO_SECRET'
}
env is set as NEXTAUTH_SECRET=MYSECRETSNAPBOOK
Code:
export default NextAuth({
providers: [
GoogleProvider({
clientId: process.env.GOOGLE_CLIENT_ID,
clientSecret: process.env.GOOGLE_CLIENT_SECRET,
}),
],
pages: {
signIn: '/auth/signin',
},
callbacks: {
async session({ session, token, user }) {
session.user.username = session.user.name
.split(' ')
.join('')
.toLocaleLowerCase()
session.user.uid = token.sub
return session
},
},
})
Here is the Fix,
In .env file (or your vercel env) add NEXT_PUBLIC_SECRET=anything (Make sure you have NEXT_PUBLIC_SECRET name as it is)
Add a secret option in [...nextauth].js
providers: [//Your providers],
secret: process.env.NEXT_PUBLIC_SECRET
Make sure you don't use 7beta version. Up or Downgrade it to 4.1.2 (npm i next-auth#4.1.2)

Resources