简体   繁体   中英

client fetch error on live website built using next.js

Hi I have tried all things possible to find out what could be causing above error on my live website built using NEXTJS.

I have noticed that this error happens whenever I reload the website.

I also notice that whenever I try to login using userName and password, I am able to do that without any errors in local host and also using https://codesandbox.io . But on the live site I get a server error "problem with the server configuration.".

when I scroll further on my developer tools I find the following additional information.

Unexpected token < in JSON at position 0 {error: {…}, path: "session", message: "Unexpected token < in JSON at position 0"

I have added the following environment variables in vercel

NEXTAUTH_URL = https://****.vercel.app/
MONGODB_URI = mongodb+srv://****@cluster0.9kc5p.mongodb.net/*****?retryWrites=true&w=majority

my [...nextauth].js file is as below

import NextAuth from "next-auth";
import CredentialsProviders from "next-auth/providers/credentials";
import { verifyPassword } from "../../../lib/hashedPassword";

import clientPromise from "../../../lib/mongodb";

export default NextAuth({
  session: {
    strategy: "jwt"
  } /* check other providers you may add database etc */,
  providers: [
    CredentialsProviders({
      /* authorize will be called when it receives incoming login req */
      async authorize(credentials) {
        const client = await clientPromise;
        const db = client.db();
        /* check if we have user or email */
        const usersCollection = await db.collection("users");

        const user = await usersCollection.findOne({
          $or: [
            { email: credentials.email },
            { userName: credentials.userName }
          ]
        });

        if (!user) {
          throw new Error("No user found");
        }
        const isvalid = await verifyPassword(
          credentials.password,
          user.password
        );

        if (!isvalid) {
          throw new Error("password is invalid");
        }

        return {
          email: user.email
        }; 
      }
    })
  ]
});

my login page is as below

import Button from "../../UI/Button/Button";
import Input from "../../UI/Input/Input";
import Card from "../../UI/card/Card";
import classes from "./Login.module.css";
import Link from "next/link";
import { useForm } from "react-hook-form";
import { signIn, getSession } from "next-auth/react";
import { useRouter } from "next/router";

const Login = () => {
  const route = useRouter();
  const {
    register,
    handleSubmit,
    formState: { errors }
  } = useForm();

  const submittedFormHandler = async (userInputs) => {
    const result = await signIn("credentials", {
      redirect: false,
      email: userInputs.userNameEmail,
      userName: userInputs.userNameEmail,
      password: userInputs.password
    }); /* result will always resolve */
    if (!result.error) {
      route.replace("/");
    }
  };

  return (
    <>          

      <Card className={classes.login}>
        <form onSubmit={handleSubmit(submittedFormHandler)}>
          
          <Input
            htmlFor="userNameEmail"
            id="userNameEmail"
            label="UserName or Email"
            input={{
              type: "text",
              ...register("userNameEmail", { required: true})
            }}
          ></Input>
          <span className={classes.spanning}>
            {errors.userName &&
              "Enter userName or Email at least four characters"}
          </span>

          <Input
            htmlFor="password"
            id="password"
            label="Enter Password"
            input={{
              type: "password",
              ...register("password", { required: true, minLength: 8 })
            }} 
          ></Input>
          <span className={classes.spanning}>
            {errors.password && "password should be at least 8 characters"}
          </span>
          <div className={classes.password}>
            <Button type="submit">Submit</Button>
            <Link href="/ForgotPassword">Forgot Password ?</Link>
          </div>
          <Link href="/NewUser" className={classes.link}>
            Create Account New User
          </Link>
        </form>
      </Card>
    </>
  );
};


export async function getServerSideProps(context) {
  const session = await getSession({
    req: context.req
  }); //returns session obj or null
  if (session) {
    return {
      redirect: {
        destination: "/",
        permanent: false
      }
    };
  }
  return {
    props: { session }
  };
}

export default Login;

what could be the problem? please assist

I faced the same problem, but i was using mysql as database and i didn't use the auth file middleware that suggest next-auth to handle the providers, instead i created a separated file to handle sequelize (in your case will be the orm with the database you're using).

I fixed it adding dialectModule to the propertys of the class Sequelize

const db = new Sequelize(`${process.env.DB_URI}`, {
  database: process.env.DB_NAME,
  logging: false,
  dialect: "mssql",
  dialectModule: require("mysql2"),
});

I also have this problem. They said on the doc that make sure you define NEXTAUTH_URL variable correctly. If you use Vercel to host, then the content of the variable should be only the url without quote. For example, https:project.vercel.app .

If not solved, try changing the [...nextauth].ts file to a more simple version. I got this error when I tried doing things with database in the callback (mongodb in my case) like this

 async jwt({ token }) {
    let role:Role = 'user'
    if (!token.email) throw Error('no email provided with token')
    let user = await getUser(token.email)
    if (user?.isAdmin) role = 'admin'
    return {...token, role}
 }

After removing this, my problem is solved. In your case, you could try removing anything that deals with the database.

After I got that working, I added this callback function instead

 async jwt({ token }) {
    let role:Role = 'user'
    if (!token.email) throw Error('no email provided with token')
    const client = await clientPromise
    const collection = client.db().collection('users')
    const user = await collection.findOne({email:token.email})
    if (user?.isAdmin) role = 'admin'
    return {...token, role}
}

The only difference is that the first one use mongoose, and the second one doesn't. The approach of the second one is taken from https://github.com/vercel/next.js/tree/canary/examples/with-mongodb

Disclaimer: I don't know why it worked.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM