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

CallbackRouteError on Credentials when following docs #11074

Closed
theswampire opened this issue Jun 4, 2024 · 38 comments · Fixed by #11469
Closed

CallbackRouteError on Credentials when following docs #11074

theswampire opened this issue Jun 4, 2024 · 38 comments · Fixed by #11469
Labels
bug Something isn't working providers triage Unseen or unconfirmed by a maintainer yet. Provide extra information in the meantime.

Comments

@theswampire
Copy link

Provider type

Credentials

Environment

System:
    OS: Linux 5.15 Ubuntu 22.04.3 LTS 22.04.3 LTS (Jammy Jellyfish)
    CPU: (16) x64 13th Gen Intel(R) Core(TM) i7-1360P
    Memory: 10.10 GB / 15.47 GB
    Container: Yes
    Shell: 5.1.16 - /bin/bash
  Binaries:
    Node: 20.14.0 - ~/.nvm/versions/node/v20.14.0/bin/node
    npm: 10.7.0 - ~/.nvm/versions/node/v20.14.0/bin/npm
    pnpm: 9.1.4 - ~/.nvm/versions/node/v20.14.0/bin/pnpm
  npmPackages:
    next: 14.2.3 => 14.2.3 
    next-auth: 5.0.0-beta.19 => 5.0.0-beta.19 
    react: ^18 => 18.3.1 

Reproduction URL

https://github.com/theswampire/authjs-bug-reproduction

Describe the issue

When using the Credentials Provider, submitting a wrong password throws an CallbackRouteError. I tested it on 5.0.0-beta.18, 17 and 16 too but they throw CredentialsSignIn instead.
I followed the v5 docs for setting up Nextjs and the Credentials Provider step by step thus this should be unexpected behaviour.

This is the auth.ts file:

// auth.ts
import NextAuth from "next-auth";
import Credentials from "next-auth/providers/credentials";

export const { handlers, signIn, signOut, auth } = NextAuth({
  providers: [
    Credentials({
      credentials: {
        password: {},
      },

      authorize: async (credentials) => {
        if (credentials.password !== "password") {
          return null;
        }
        return { id: "admin", name: "admin" };
      },
    }),
  ],

  pages: {
    signIn: "/signin",
  },
});

The SignIn page looks like this:

import { signIn } from "@/auth";

export default function SignIn() {
  return (
    <form
      className="flex flex-col max-w-sm gap-2"
      action={async (formData) => {
        "use server";
        await signIn("credentials", formData);
      }}
    >
      <label>
        Password
        <input name="password" type="password" className="border" />
        <input name="redirectTo" type="hidden" value="/secure" />
      </label>
      <span>Password is &quot;password&quot;</span>
      <button className="bg-neutral-300">Sign In</button>
    </form>
  );
}

I tried to wrap the signIn call in a try-catch like in #11010 but that obviously didn't fix the underlying issue.

According to the documentation, the CallbackRouteError using the Credentials Provider means that either the authorize or another callback throws but I didn't overwrite any callbacks nor should authorize throw anything. Furthermore, if I remember correctly, when setting redirect to false, the SignInResponse contained ok: true and a Configuration error which I find odd.

How to reproduce

Enter anything but the correct password "password" and then the exception should be thrown.
Using the correct password works just fine.

Expected behavior

Don't throw an exception.

@theswampire theswampire added bug Something isn't working providers triage Unseen or unconfirmed by a maintainer yet. Provide extra information in the meantime. labels Jun 4, 2024
@shunkica
Copy link

shunkica commented Jun 7, 2024

For me, just returning null from authorize() throws the CallbackRouteError

@bibaswan7
Copy link

i am facing the exact same issue

@bibaswan7
Copy link

I am not sure if its done intentionally but I went through the next-auth code and figured out that, even though CredentialsSignin error is being thrown, it is then passed to CallbackRouteError, which is why we are getting CallbackRouteError.
catch (e) { if (e instanceof AuthError) throw e; const error = new CallbackRouteError(e, { provider: provider.id }); logger.debug("callback route error details", { method, query, body }); throw error; }

here as you can see, catch recieves CredentialsSignin error. Since it is an instance of Error and not of AuthError, it skips the conditional, then rest is pretty much self explanatory.

In order to solve this issue, if its an CredentialsSignin error, then instead of checking error.type === 'CredentialsSignin', what you can do is
error.cause.err.code === 'credentials'

@jessethomson
Copy link

Experiencing the same issue as others: If I return null from authorize, it throws this error.

This issue only started happening after upgrading to the latest beta. I went from 5.0.0-beta.4 to 5.0.0-beta.19 so I'm not sure which version in between those specifically causes this issue.

@nprdservice3
Copy link

I am not sure if its done intentionally but I went through the next-auth code and figured out that, even though CredentialsSignin error is being thrown, it is then passed to CallbackRouteError, which is why we are getting CallbackRouteError. catch (e) { if (e instanceof AuthError) throw e; const error = new CallbackRouteError(e, { provider: provider.id }); logger.debug("callback route error details", { method, query, body }); throw error; }

here as you can see, catch recieves CredentialsSignin error. Since it is an instance of Error and not of AuthError, it skips the conditional, then rest is pretty much self explanatory.

In order to solve this issue, if its an CredentialsSignin error, then instead of checking error.type === 'CredentialsSignin', what you can do is error.cause.err.code === 'credentials'

thanks it worked

@ondery
Copy link

ondery commented Jun 11, 2024

I am not sure if its done intentionally but I went through the next-auth code and figured out that, even though CredentialsSignin error is being thrown, it is then passed to CallbackRouteError, which is why we are getting CallbackRouteError. catch (e) { if (e instanceof AuthError) throw e; const error = new CallbackRouteError(e, { provider: provider.id }); logger.debug("callback route error details", { method, query, body }); throw error; }

here as you can see, catch recieves CredentialsSignin error. Since it is an instance of Error and not of AuthError, it skips the conditional, then rest is pretty much self explanatory.

In order to solve this issue, if its an CredentialsSignin error, then instead of checking error.type === 'CredentialsSignin', what you can do is error.cause.err.code === 'credentials'

When done this way, it will give the same error again if there is a connection problem with the database.

@bibaswan7
Copy link

@ondery what error are you getting? mind sharing the code snippets?

@danbeo95
Copy link

The same issue with 5.0.0-beta.19

@azizali

This comment has been minimized.

@ondery
Copy link

ondery commented Jun 13, 2024

@ondery what error are you getting? mind sharing the code snippets?

@bibaswan7 error.cause.err.code === 'credentials' will give true in case of database connection problems too unfortunately.

@Kupinaaa
Copy link

Kupinaaa commented Jun 14, 2024

@bibaswan7 I came to the same conclusion, but since I'm using typescript, it screams at me saying that property of code does not exist on type Error. Does anyone know a way to do typing properly with this weird wrapping, as well as @ondery mentioned, a way to disambiguate this error further?

I looked into the typing issue a bit more and found commit d089923 , where the typing of CredentialsSignin is changed from extending SignInError to extending Error. This further ambiguities the typing on the error. I found the issue for it in #11155

@Ali-Raza764
Copy link

I think I have a fix of just signing in and handling an error if the password is incorrect. Instead of using signIn() function from the @/auth.js file we can do somthing like this in the signinForm:

import { signIn } from "next-auth/react";
import Link from "next/link";
import { useRouter } from "next/navigation";
import { useState } from "react";
import Providers from "../components/Providers";

const SignInForm = () => {
  const [loading, setLoading] = useState(false);
  const router = useRouter();
  const [error, setError] = useState("");

  const handleSubmit = async (e) => {
    e.preventDefault();
    const email = e.target.email.value;
    const password = e.target.password.value;

    try {
      setLoading(true);
      setError("");
      const res = await signIn("credentials", {
        redirect: false,
        email,
        password,
      });

      //* The res here has no credentials data only error:true or error:null so we can manage the state based on that
      //* Next auth does not send the data due to security reasons
      if (res.error === null) {
        router.push("/protected");
      }
      if (res.error) {
        setError("Check Your Email Or Password");
      }
    } catch (error) {
      console.error(error.message);
    } finally {
      setLoading(false);
    }
  };

  return (
    <div className="shadow bg-gray-400 p-4 rounded-md m-2 min-w-[20rem]">
      <form onSubmit={handleSubmit} className="flex flex-col gap-4">
        <input
          type="text"
          name="email"
          placeholder="Email"
          className="border-b-2 border-gray-400 focus:border-red-500 outline-none  p-2 transition disabled:border-none disabled:bg-gray-400"
          required
          disabled={loading}
        />
        <input
          type="password"
          name="password"
          placeholder="Password"
          className="border-b-2 border-gray-400 focus:border-red-500 outline-none  p-2 transition disabled:border-none disabled:bg-gray-400"
          required
          disabled={loading}
        />
        <p className="text-red-500">{error}</p>
        <button
          type="submit"
          className="p-2 px-4 bg-gray-800 rounded-md text-white disabled:border-none disabled:bg-gray-600"
          disabled={loading}
        >
          Submit
        </button>
      </form>
      <div className="my-2 w-full text-center"> Or</div>
      <div className="w-full">
        <Providers />
      </div>
      <Link href="/auth/signup">SignUp</Link>
    </div>
  );
};

export default SignInForm;

If the signIn() functions throws an error Then it means that The credentials are invalid...
And If you are storing your user credentials in a database you can handle that authentication from the auth.js file using a server action:

import GitHub from "next-auth/providers/github";
import Google from "next-auth/providers/google";
import CredentialsProvider from "next-auth/providers/credentials";
import {
  SignInWithEmailAndPassword,
  oauthSignIn,
} from "@/actions/user/user.actions";

const providers = [
  Google,
  GitHub,
  CredentialsProvider({
    name: "Credentials",
    credentials: {
      email: { label: "Email", type: "email" },
      password: { label: "Password", type: "password" },
    },
    async authorize(credentials) {
      const user = await SignInWithEmailAndPassword(credentials); // User verification logic
      if (user.status === 400) {
        return null;
      }
      return user.data;
    },
  }),
];

export const providerMap = providers.map((provider) => {
  if (typeof provider === "function") {
    const providerData = provider();
    return { id: providerData.id, name: providerData.name };
  } else {
    return { id: provider.id, name: provider.name };
  }
});

export const { handlers, auth, signIn, signOut, unstable_update } = NextAuth({
  providers,
  pages: {
    signIn: "/auth/sign-in",
  },
  callbacks: {
    async signIn({ user, account }) {
      if (account.provider === "google" || account.provider === "github") {
        const { name, email, image } = user;
        const payload = {
          name,
          email,
          avatar: image,
          authType: "Oauth",
        };

        const res = await oauthSignIn(payload);
        user.id = res.data._id.toString();
        user.isVerified = res.data.isVerified;
        user.image = res.data.avatar;

        return user;
      }
      // Default to allow sign-in
      return user;
    },
    async jwt({ trigger, token, user }) {
      // Add user information to the token during sign-in
      if (trigger === "update") {
        token.isVerified = session.user.isVerified;
      }
      if (user) {
        console.log(user);
        const id = user._id?.toString() || user.id;
        token.id = id;
        token.email = user.email;
        token.name = user.name;
        token.isVerified = user.isVerified;
        token.picture = user.avatar || user.image;
      }
      return token;
    },
    async session({ session, token }) {
      session.user.id = token.id;
      session.user.email = token.email;
      session.user.name = token.name;
      session.user.image = token.picture;
      session.user.isVerified = token.isVerified;
      return session;
    },
  },
});```
I think this pretty much works for now. If you want to see detailed implementation for this you can checkout this [repo](https://github.com/Ali-Raza764/next-auth-tookit)

@Kupinaaa
Copy link

Yeah @Ali-Raza764 That's exactly what I do currently, but I just want a bit more fine grain control over the error, and it is supposed to work, but just doesn't. For example, what if my API endpoint became unreachable and just timed out.. It would still say to check the credentials on the client side, even if they are correct. That would lead the user to try a bunch of times and then try to reset the password, which is not something I would want. Instead I want to distinguish whether it's because of the credentials (user does not exist on the token in the Callback). I think this could just be fixed with the typing, as @bibaswan7 said.

The issue for the broken types is #11155.

The types are broken in #11050

Screenshot 2024-06-14 at 11 31 09 AM

@Ali-Raza764
Copy link

Ok I do understand that. So we can wait until the new release makes a fix ?

@riky-on-devcra

This comment has been minimized.

@sambecker
Copy link

In case it's helpful, can confirm that Credentials-based error handling broke for me when switching to from beta.18 to beta.19.

Errors previously classified CredentialsSignin became classified CallbackRouteError.

@Ali-Raza764
Copy link

Ali-Raza764 commented Jun 21, 2024

What if we can customize the authorize() function to return custom errors like this #9871
And here #9099

@hillaryodinson
Copy link

I rolled back from 5.0.0-beta.19 to 5.0.0-beta.18 and it worked for me. Clearly its a bug on 5.0.0-beta.19 so until a new update comes I ll stick to the previous version

@ethanforvest
Copy link

I rolled back from 5.0.0-beta.19 to 5.0.0-beta.18 and it worked for me. Clearly its a bug on 5.0.0-beta.19 so until a new update comes I ll stick to the previous version

Yeah, downgrading fixed the issue for me too

@cherylli
Copy link

cherylli commented Jun 28, 2024

I tested it on 5.0.0-beta.18, 17 and 16 too but they throw CredentialsSignIn instead.

Exactly same issue as OP, downgrading to beta.18 didn't work

"next": "^14.2.4",
"next-auth": "^5.0.0-beta.19",

@hillaryodinson
Copy link

hillaryodinson commented Jul 1, 2024

use npm install next-auth@5.0.0-beta.18 or yarn add next-auth@5.0.0-beta.18 that should help. make sure your provider authorize returns null or user data

edit: I forgot to add yarn for yarn users. my bad

@SasquatchLV
Copy link

use npm install next-auth@5.0.0-beta.18 that should help. make sure your provider authorize returns null or user data

So which version of the code is working for you now?? Can you show an example how you got the custom errors?

@stephendewyer
Copy link

I am facing a similar issue with @auth/core:0.31.0 and @auth/sveltekit:1.1.0. The response object for signIn is always returning no error when user submits invalid credentials.
The issue in more detail: #10931.

@NitanJana
Copy link

use npm install next-auth@5.0.0-beta.18 that should help. make sure your provider authorize returns null or user data

this fixed it for me, thanks.

@cherylli
Copy link

cherylli commented Jul 7, 2024

I tested it on 5.0.0-beta.18, 17 and 16 too but they throw CredentialsSignIn instead.

Exactly same issue as OP, downgrading to beta.18 didn't work

"next": "^14.2.4",
"next-auth": "^5.0.0-beta.19",

Tried again a week later with the same code and yarn add next-auth@5.0.0-beta.18 worked for me.

Also don't throw any other errors except CredentialSignin error, it gives configuration error

so either null or CredentialSignin error will work for next-auth@5.0.0-beta.18 but they are both broken in beta.19

@dynamiclynk
Copy link

dynamiclynk commented Jul 7, 2024

downgrading from "next-auth": "^5.0.0-beta.19" to 18 allows a custom error responses to throw and be handled in the client. Can't understand abstracting this away from the developer 😕, at least default it to off and allow us to specify an process env var to enable throwing custom core authorize errors and any auth life cycle hook.

@nkghis
Copy link

nkghis commented Jul 9, 2024

use npm install next-auth@5.0.0-beta.18 or yarn add next-auth@5.0.0-beta.18 that should help. make sure your provider authorize returns null or user data

edit: I forgot to add yarn for yarn users. my bad

thanks that is work well now

@mehrwarz
Copy link

mehrwarz commented Jul 9, 2024

"next": "14.2.4",
"next-auth": "^5.0.0-beta.19",
I was able to throw my custom error in server side and send message to client. here it is: https://stackoverflow.com/questions/78627862/next-auth-signin-return-errorconfiguration-in-responce-for-invalid-credenti/78723173#78723173

@Lucifer472
Copy link

just downgrade to "next-auth": "^5.0.0-beta.18" it will fix the issue i was having the same problem.

To fix it first remove next-auth from package json then run npm i then install npm install next-auth@5.0.0-beta.18
and make sure to return null with authorize function or if you want use custom error msg like this

import { CredentialsSignin } from "next-auth";

class WrongPassword extends CredentialsSignin {
  code = "Wrong_Password";
}

const isMatch = await bcrypt.compare(password, user.password);
if (!isMatch) throw new WrongPassword();

inside of the login function

 try {
    await signIn("credentials", {
      redirect: true,
      redirectTo: defaultRedirect,
      email,
      password,
    });
  } catch (error) {
    if (error instanceof AuthError) {
      switch (error.type) {
        case "CredentialsSignin":
          return "Invalid credentials";
        case "CallbackRouteError":
          return "Something went Wrong!";
        default:
          return "Something went wrong";
      }
    }
    throw error;
  }

i hope this helps

@liamicy3aaa
Copy link

Was also seeing this issue and thought it was me! Downgrading to 5.0.0-beta.18 resolved the issue for me!

Thanks.

@mehrwarz
Copy link

mehrwarz commented Jul 19, 2024 via email

@ThangHuuVu
Copy link
Member

hi all, 🙇‍♂️ so I think it would be best to revert #11050 and fix this regression issue first, and revisit the issue that @ndom91 attempted to fix on that PR later on - please expect a release to be cut soon, thanks for your patience 🙏

@rzashakeri
Copy link

I had the same error in Version of 5.00-beta 18 and 5.0.0-beta 19 Finaly i was able to handle my custom error here and i test it out in both versions. https://stackoverflow.com/questions/78627862/next-auth-signin-return-errorconfiguration-in-responce-for-invalid-credenti/78673275#78673275 Please let me know if you have any comments. Thanks and regards Emran

________________________________ From: Liam McClelland @.> Sent: Wednesday, July 17, 2024 2:52 PM To: nextauthjs/next-auth @.> Cc: Sayed Emran Mehrwarz @.>; Comment @.> Subject: Re: [nextauthjs/next-auth] CallbackRouteError on Credentials when following docs (Issue #11074) Was also seeing this issue and thought it was me! Downgrading to 5.0.0-beta.18 resolved the issue for me! Thanks. — Reply to this email directly, view it on GitHub<#11074 (comment)>, or unsubscribehttps://github.com/notifications/unsubscribe-auth/AYAR3WFF5WORCXCY52CSUODZM3RRBAVCNFSM6AAAAABIY7UMXGVHI2DSMVQWIX3LMV43OSLTON2WKQ3PNVWWK3TUHMZDEMZUGM4DIMZTHE. You are receiving this because you commented.

many thanks
for newer version this code worked 💙

@Ashraful-Mijan
Copy link

use npm install next-auth@5.0.0-beta.18 that should help. make sure your provider authorize returns null or user data

this fixed it for me, thanks.

Can you show how you got the errors?

@luco
Copy link

luco commented Oct 8, 2024

@maxpaleo
Copy link

I've been working with Next auth for about a week now, and at this point, I wonder why people actually even use this library. I mean, I am guessing that everyone starts using it to integrate auth in their apps quickly, and then end up on spending hours working around the countless issues?

Next, auth seems to be written by a team that believes their definite opinions on handling auth are the only way to handle it. The library is the exact opposite of "Flexible."

I guess it makes sense if you only want to use some Oauth login with 0 interactions with the DB, but for anything else, why on earth do we keep working around their "single opinion auth flow" to be able to implement authentication in our apps?

And if only the docs actually mentioned the hundreds of roadblocks they've implemented to allow for custom behavior, but no, absolutely nothing.

It's a shame Lucia has been deprecated. I can't wait for someone to release a complete, unopinionated auth lib that is actually built around the idea of a lib, not some single team's opinionated piece of code that seriously lacks documentation.

For anyone reading this, if you haven't spend more than a few hours on resolving next auth issues: I'd recommend staying away, and simply build auth from scratch. You'll spend less time implementing a single JWT flow, interactions with your db, and error handling.

@cool3rain
Copy link

I've been working with Next auth for about a week now, and at this point, I wonder why people actually even use this library. I mean, I am guessing that everyone starts using it to integrate auth in their apps quickly, and then end up on spending hours working around the countless issues?

Next, auth seems to be written by a team that believes their definite opinions on handling auth are the only way to handle it. The library is the exact opposite of "Flexible."

I guess it makes sense if you only want to use some Oauth login with 0 interactions with the DB, but for anything else, why on earth do we keep working around their "single opinion auth flow" to be able to implement authentication in our apps?

And if only the docs actually mentioned the hundreds of roadblocks they've implemented to allow for custom behavior, but no, absolutely nothing.

It's a shame Lucia has been deprecated. I can't wait for someone to release a complete, unopinionated auth lib that is actually built around the idea of a lib, not some single team's opinionated piece of code that seriously lacks documentation.

For anyone reading this, if you haven't spend more than a few hours on resolving next auth issues: I'd recommend staying away, and simply build auth from scratch. You'll spend less time implementing a single JWT flow, interactions with your db, and error handling.

I couldn't agree more! next-auth@5.0.0-beta is a complete waste of time.

@tapz
Copy link

tapz commented Jan 3, 2025

I've been working with Next auth for about a week now, and at this point, I wonder why people actually even use this library. I mean, I am guessing that everyone starts using it to integrate auth in their apps quickly, and then end up on spending hours working around the countless issues?

Could not agree more. The only reason I use Next auth is that it provides the Facebook, Google etc authentications. Though, the time I have used solving weird issues and non-flexibility could have been used to write 20 integrations to different providers' services.

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

Successfully merging a pull request may close this issue.