susanliu
susanliu

Reputation: 93

Next-Auth signout error: TypeError: Response body object should not be disturbed or locked

I was writing a website with signIn and signOut function from next-auth/react. But sometimes when I sign out, error showing TypeError: Response body object should not be disturbed or locked shows on the terminal. Although it sometimes still signOut properly, but other times it just redirect to the main page and I have to click the signOut button again to signOut. I guess the problem occurs in how I handle signIn and here's my code:

const handleSubmit = async(e: React.FormEvent<HTMLFormElement>) => {
    e.preventDefault();
    const result=await signIn("credentials", {
      email,
      password,
      callbackUrl: `${publicEnv.NEXT_PUBLIC_BASE_URL}/AboutMe`,
      redirect:false,
    });
    if((result)&&(result.error==="CredentialsSignin")){
      toast({
        variant: "destructive",
        description: "輸入的帳號不存在或有誤,請再次輸入",
      });
    }
    else if(result&&result.error==="CallbackRouteError"){
      toast({
        variant: "destructive",
        description: "輸入的密碼不正確,請再次輸入",
      });
    }
    else if (result && !result.error) {
      
      router.push(`${publicEnv.NEXT_PUBLIC_BASE_URL}/AboutMe`);
      router.refresh();
      setOpen(false);
    }
  };

And here's my CredentialsProvider.ts:

import CredentialsProvider from "next-auth/providers/credentials";

import bcrypt from "bcryptjs";
import { desc, eq } from "drizzle-orm";

import { db } from "@/db";
import { experiencesTable, usersTable } from "@/db/schema";
import { authSchema } from "@/validators/auth";

export default CredentialsProvider({
  name: "credentials",
  credentials: {
    email: { label: "Email", type: "text" },
    username: { label: "Userame", type: "text", optional: true },
    password: { label: "Password", type: "password"},
    mobile:{ label:"Mobile", type:"text", optional: true},
    school:{ label:"School", type:"text", optional: true}
  },
  async authorize(credentials) {
    let validatedCredentials: {
      email: string;
      username?: string;
      password: string;
      mobile?:string;
      school?:string;
    };

    try {
      validatedCredentials = authSchema.parse(credentials);
    } catch (error) {
      console.log("Wrong credentials. Try again.");
      return null;
    }
    const { email, password } = validatedCredentials;

    const [existedUser] = await db
      .select({
        id: usersTable.displayId,
        username: usersTable.username,
        email: usersTable.email,
        provider: usersTable.provider,
        hashedPassword: usersTable.hashedPassword,
        mobile: usersTable.mobile,
        authority: usersTable.authority,
        school: experiencesTable.school
      })
      .from(usersTable)
      .leftJoin(experiencesTable, eq(usersTable.email, experiencesTable.email))
      .orderBy(desc(experiencesTable.semester))
      .where(eq(usersTable.email, email.toLowerCase()))
      .limit(1)
      .execute();
    if(!existedUser){
      return null;
    }
    const isValid = await bcrypt.compare(password, existedUser.hashedPassword);
    if (!isValid) {
      throw new Error("輸入的密碼不正確,請再次輸入");
    }
    return {
      email: existedUser.email,
      username: existedUser.username,
      id: existedUser.id,
      mobile: existedUser.mobile,
      authority:existedUser.authority,
      school: existedUser.school??""
    };
  },
});

The signIn and signOut works fine before I add result(the variable returned in signIn function) and throw new Error in CredentialsProvider.ts(before both !existedUser and !isValid return null), so the error might occurs because of router.push() and router.refresh(). Because I want to toast different words when users type their account and password wrong, so I guess I still needs result(the variable returned in signIn function) to see if it is a CredentialsSignin error or CallbackRouteError.

I want to know whether my guess of why the error is showing is right and how to fix it without removing the part where I determine what kind of error is the signIn function returning. Thanks!

Providing my auth/signout if needed:

"use client";

import { useEffect } from "react";

import { signOut, useSession } from "next-auth/react";
import { useRouter } from "next/navigation";

import { publicEnv } from "@/lib/env/public";

function SignOutPage() {
  const { data: session } = useSession();
  const router = useRouter();
  useEffect(() => {
    if (session) {
      signOut({ callbackUrl: publicEnv.NEXT_PUBLIC_BASE_URL });
    }
    router.push("/");
  }, [session, router]);

  return <></>;
}

export default SignOutPage;

Also how I signOut:

<a href="/auth/signout" className="hover:opacity-70">登出</a>

Upvotes: 0

Views: 121

Answers (0)

Related Questions