Skip to content

This issue was moved to a discussion.

You can continue the conversation there. Go to discussion →

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

can not handle error from AuthError v-beta #11747

Closed
h-rajabi opened this issue Sep 1, 2024 · 15 comments
Closed

can not handle error from AuthError v-beta #11747

h-rajabi opened this issue Sep 1, 2024 · 15 comments
Labels
bug Something isn't working triage Unseen or unconfirmed by a maintainer yet. Provide extra information in the meantime.

Comments

@h-rajabi
Copy link

h-rajabi commented Sep 1, 2024

Environment

auth.config file

      id: "credentials",
      async authorize(credentials) {
        if (!credentials) {
          console.log("first");
          return null;
        }
        try {
          const response = await axiosInstance.post("/api/v1/auth", {
            phoneNumber: credentials.phone,
            password: credentials.password,
          });

          if (response.status === 200 && response.data) {
            return response.data;
          } else if (!response.data) {
            return null;
          } else {
            throw new Error(`Unexpected status code: ${response.status}`);
          }
        } catch (error: any) {
          if (error.response) {
            // Handle specific status codes
            switch (error.response.status) {
              case 400:
                throw new Error("Invalid credentials.");
              case 401:
                throw new Error(
                  "Unauthorized. Please check your username and password."
                );
              case 403:
                throw new Error("Access forbidden.");
              case 500:
                throw new Error("Server error. Please try again later.");
              default:
                throw new Error("An error occurred during login.");
            }
          } else if (error.request) {
            // No response was received from the server
            throw new Error(
              "No response from server. Please check your network connection."
            );
          } else {
            // Other errors
            throw new Error("Login failed due to an unexpected error.");
          }
        }

      },
    }),

my server action

  const validateData = UserLoginScema.safeParse(values);
  if (validateData.success) {
    const phone = validateData.data.userName;
    const password = validateData.data.password;
    try {
      const res=await signIn("credentials", {
        phone,
        password,
        redirect: false,
      });
      // console.log(res);
      
      return { statuscode: 200, message: "test success" };
    } catch (error) {
      if (error instanceof AuthError) {
        
        switch (error.type) {
          case "CredentialsSignin":
            return {
              statuscode: 400,
              message: "phoneNumber or password is not corect",
            };
          default:
            return { statuscode: 400, message: "something went wrong" };
        }
      }
      throw error;
    }
  }
  return { statuscode: 400, message: "invalid credentails" };
};```

### Reproduction URL

https://github.com/h-rajabi/test-credentials.git

### Describe the issue

in my log terminal server i get this error message 
```CredentialsSignin: Read more at https://errors.authjs.dev#credentialssignin
    at Module.callback (webpack-internal:///(action-browser)/./node_modules/@auth/core/lib/actions/callback/index.js:230:23)

and then i try to wen user can`t login throw new Error("some error)
or ``` throw new AuthError("some error")```
but this not work and get CallBackError

ervery thing is work but this message show in server and this not good

How to reproduce

.

Expected behavior

all error must handle and don`t show anything in my server log

@h-rajabi h-rajabi added bug Something isn't working triage Unseen or unconfirmed by a maintainer yet. Provide extra information in the meantime. labels Sep 1, 2024
@h-rajabi
Copy link
Author

h-rajabi commented Sep 1, 2024

i seen this error in any project with next-auth-beta in github

@LorysHamadache
Copy link

LorysHamadache commented Sep 3, 2024

I managed to have my custom error message by extending the CredentialsSignin class like that:

in auth.ts

export class UserDoesNotExistError extends CredentialsSignin {
    code = "AuthError"
    message = "User does not exist - Please check credentials"
}

export class PasswordInccorectError extends CredentialsSignin {
    code = "AuthError"
    message = "Password is incorrect - Please check credentials"
}

..... 

async authorize(credentials, request) {
....
try {
    if (!user) { throw new UserDoesNotExistError(); }
    if (!isPasswordValid) { throw new PasswordInccorectError(); }
    else return {....}
}
catch (error) {
    if ((error instanceof UserDoesNotExistError) || (error instanceof PasswordInccorectError)) {
       throw error;
    } else {
        throw new Error("Unexpected error occurred during authorization");
    }
}

action.ts

export async function doCredentialLogin(formData: FormData) {
    try {
        const response = await signIn("credentials", {
            email: formData.get("email") as string,
            password: formData.get("password") as string,
            redirect: false,
        });
        return response;
    }
    catch (error: any) {
        let errorMessage = "An unknown error occurred - Please contact the administrator";
        if (error.message && error.message != "") errorMessage = error.message;
        const response = { error: errorMessage };
        return response;
    }
}

This is a test example. Of course, for any production work, you should not tell the user if its a username or password error.
image

@h-rajabi
Copy link
Author

h-rajabi commented Sep 3, 2024

when you show user does not exist or password is not correct CredentialsSignin error show up in your log server ?
like this :

[auth][error] CredentialsSignin: Password is incorrect - Please check credentials
    at Object.authorize (webpack-internal:///(action-browser)/./src/config/auth.config.ts:89:23)
    at Module.callback (webpack-internal:///(action-browser)/./node_modules/@auth/core/lib/actions/callback/index.js:225:54)
    at AuthInternal (webpack-internal:///(action-browser)/./node_modules/@auth/core/lib/index.js:66:77)
    at process.processTicksAndRejections (node:internal/process/task_queues:95:5)
    at async Auth (webpack-internal:///(action-browser)/./node_modules/@auth/core/index.js:126:34)
    at async signIn (webpack-internal:///(action-browser)/./node_modules/next-auth/lib/actions.js:51:17)
    at async $$ACTION_0 (webpack-internal:///(action-browser)/./src/actions/login-action.ts:27:25)
    at async /home/hossein/programing/insurance/node_modules/next/dist/compiled/next-server/app-page.runtime.dev.js:39:418
    at async rw (/home/hossein/programing/insurance/node_modules/next/dist/compiled/next-server/app-page.runtime.dev.js:38:7978)
    at async r6 (/home/hossein/programing/insurance/node_modules/next/dist/compiled/next-server/app-page.runtime.dev.js:41:1256)```

@jelmd
Copy link

jelmd commented Sep 11, 2024

To get rid off the DoS attack vector (log junk) and the annoying Read more at https://errors.authjs.dev#credentialssignin clutter I use in v5-beta-20:

class CredentialsError extends CredentialsSignin {
	constructor(message: string) {
		super(message);
		this.message = message;
	}
	override stack = '' ;
}

and throw it like throw new CredentialsError(user + ' not verified'). At least in beta-20 the message gets logged, but the default UI shows always: Sign in failed. Check the details you provided are correct., which is ok for me: If support asks, I can grep the problem easily from the log and the UI does not reveal too much info about existing user or password.

@jhoanborges
Copy link

CredentialsSignin

This did not worked for me. I'm still facing this issue, i can not return a custom error.

@DavidArmendariz
Copy link

Same problem here. Stuck hours for this silly error.

@Redbeardjunior

This comment has been minimized.

@Ali-Raza764
Copy link

@jhoanborges which next-auth version are you using?

@Ali-Raza764
Copy link

the latest version clearly states how you can throw a custom error it must work for you.

import NextAuth, { CredentialsSignin } from "next-auth"
import Credentials from "next-auth/providers/credentials"
 
class InvalidLoginError extends CredentialsSignin {
  code = "Invalid identifier or password"
}
 
export const { handlers, auth } = NextAuth({
  providers: [
    Credentials({
      credentials: {
        username: { label: "Username" },
        password: { label: "Password", type: "password" },
      },
      async authorize(credentials) {
        throw new InvalidLoginError()
      },
    }),
  ],
})

Read the docs https://authjs.dev/getting-started/providers/credentials#custom-error-messages

@Redbeardjunior
Copy link

the latest version clearly states how you can throw a custom error it must work for you.

import NextAuth, { CredentialsSignin } from "next-auth"
import Credentials from "next-auth/providers/credentials"
 
class InvalidLoginError extends CredentialsSignin {
  code = "Invalid identifier or password"
}
 
export const { handlers, auth } = NextAuth({
  providers: [
    Credentials({
      credentials: {
        username: { label: "Username" },
        password: { label: "Password", type: "password" },
      },
      async authorize(credentials) {
        throw new InvalidLoginError()
      },
    }),
  ],
})

Read the docs https://authjs.dev/getting-started/providers/credentials#custom-error-messages

Did you try and verified, if itg work on your end ? I'm still getting some mest up errors with trying to implement something similar.

@Ali-Raza764
Copy link

Yeah certainly I can show you how I handled the custom error.
I simply call the signIn() from import { signIn } from "next-auth/react"; like this

const res = await signIn("credentials", {
        redirect: true,
        redirectTo: "/",
        email,
        password,
      });

This causes the page to refresh if the signIn is successfull or not then i recieve the error in the querry params like this

  const searchParams = useSearchParams();
  const error = searchParams.get("error");
  const message = searchParams.get("code");

And display the errror if any, else it will be redirected to the specific redirect url.
Full Code

"use client";
import { useState } from "react";
import { signIn } from "next-auth/react";
import { useSearchParams } from "next/navigation";

// Helper function to validate email format
const validateEmail = (email) => {
  const emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
  return emailRegex.test(email);
};

const SignIn = () => {
  const searchParams = useSearchParams();
  const error = searchParams.get("error");
  const message = searchParams.get("code");

  const [loading, setLoading] = useState(false);

  const handleSubmit = async (e) => {
    e.preventDefault();
    setLoading(true);

    const email = e.target.email.value;
    const password = e.target.password.value;

    // Validate email
    if (!validateEmail(email)) {
      alert("Invalid email format");
      setLoading(false);
      return;
    }

    try {
      const res = await signIn("credentials", {
        redirect: true,
        redirectTo: "/",
        email,
        password,
      });
      console.log(res);
    } catch (error) {
      console.error("Sign-in failed", error);
    }

    setLoading(false);
  };

  return (
    <div className="min-h-screen flex items-center justify-center">
      <div className="w-full max-w-md p-6 bg-gray-800 rounded-lg shadow-lg">
        <h2 className="text-3xl font-semibold text-center text-white mb-8">
          Sign In
        </h2>
        <form onSubmit={handleSubmit} className="space-y-6">
          {/* Email Field */}
          <div>
            <label htmlFor="email" className="block text-sm text-gray-400">
              Email
            </label>
            <input
              type="email"
              id="email"
              name="email"
              required
              className="w-full px-4 py-2 mt-2 text-white bg-gray-700 border border-gray-600 rounded-md focus:ring-2 focus:ring-indigo-500 focus:outline-none transition duration-300"
              placeholder="Enter your email"
            />
          </div>

          {/* Password Field */}
          <div>
            <label htmlFor="password" className="block text-sm text-gray-400">
              Password
            </label>
            <input
              type="password"
              id="password"
              name="password"
              required
              className="w-full px-4 py-2 mt-2 text-white bg-gray-700 border border-gray-600 rounded-md focus:ring-2 focus:ring-indigo-500 focus:outline-none transition duration-300"
              placeholder="Enter your password"
            />
          </div>

          {/* General Errors */}
          {error && (
            <p className="text-red-500 text-sm text-center">{message}</p>
          )}

          {/* Submit Button */}
          <div>
            <button
              type="submit"
              disabled={loading}
              className={`w-full px-4 py-2 text-lg font-medium text-white bg-indigo-600 rounded-md transition duration-300 ${
                loading ? "opacity-50 cursor-not-allowed" : "hover:bg-indigo-500"
              }`}
            >
              {loading ? "Signing In..." : "Sign In"}
            </button>
          </div>
        </form>
      </div>
    </div>
  );
};

export default SignIn;

image

@Ali-Raza764
Copy link

For your assurance I have replicated the same procedure using a server action and no refresh error messages:

"use server";

import { signIn } from "@/auth";

export async function signInCredentials(payload) {
  try {
    const result = await signIn("credentials", {
      ...payload,
      redirect: false,
    });

    return { success: true };
  } catch (error) {
    // Check if the error is an instance of Error and has a message
    if (error instanceof Error) {
      return { success: false, message: error.message };
    }

    // Fallback error message
    return { success: false, message: "An unexpected error occurred" };
  }
}

For the Login component:

"use client";
import { useState } from "react";
import { signInCredentials } from "@/actions/signIn";

export default function LoginPage() {
  const [error, setError] = useState("");

  const handleSubmit = async (e) => {
    e.preventDefault();
    setError("");
    const payload = {
      email: e.target.email.value,
      password: e.target.password.value,
    };
    const res = await signInCredentials(payload);
    console.log(res);
    if (!res.success) {
      setError(res.message);
    }
  };

  return (
    <div className="min-h-screen flex flex-col justify-center py-12 sm:px-6 lg:px-8">
      <div className="sm:mx-auto sm:w-full sm:max-w-md">
        <h2 className="mt-6 text-center text-3xl font-extrabold">
          Login to your account
        </h2>
      </div>

      <div className="mt-8 sm:mx-auto sm:w-full sm:max-w-md">
        <div className="bg-gray-900 py-8 px-4 shadow sm:rounded-lg sm:px-10">
          {error && (
            <div
              className="mb-4 bg-red-100 border border-red-400 text-red-700 px-4 py-3 rounded relative"
              role="alert"
            >
              <span className="block sm:inline">{error}</span>
            </div>
          )}
          <form className="space-y-6" onSubmit={handleSubmit}>
            <div>
              <label
                htmlFor="email"
                className="block text-sm font-medium text-gray-400"
              >
                Email address
              </label>
              <div className="mt-1">
                <input
                  id="email"
                  name="email"
                  type="email"
                  autoComplete="email"
                  required
                  className="appearance-none block w-full px-3 py-2 border border-gray-300 rounded-md shadow-sm placeholder-gray-400 focus:outline-none focus:ring-indigo-500 focus:border-indigo-500 sm:text-sm"
                />
              </div>
            </div>

            <div>
              <label
                htmlFor="password"
                className="block text-sm font-medium text-gray-400"
              >
                Password
              </label>
              <div className="mt-1">
                <input
                  id="password"
                  name="password"
                  type="password"
                  autoComplete="current-password"
                  required
                  className="appearance-none block w-full px-3 py-2 border border-gray-300 rounded-md shadow-sm placeholder-gray-400 focus:outline-none focus:ring-indigo-500 focus:border-indigo-500 sm:text-sm"
                />
              </div>
            </div>

            <div>
              <button
                type="submit"
                className="w-full flex justify-center py-2 px-4 border border-transparent rounded-md shadow-sm text-sm font-medium text-white bg-indigo-600 hover:bg-indigo-700 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-indigo-500"
              >
                Sign in
              </button>
            </div>
          </form>
        </div>
      </div>
    </div>
  );
}

image

@Ali-Raza764
Copy link

when you show user does not exist or password is not correct CredentialsSignin error show up in your log server ? like this :

[auth][error] CredentialsSignin: Password is incorrect - Please check credentials
    at Object.authorize (webpack-internal:///(action-browser)/./src/config/auth.config.ts:89:23)
    at Module.callback (webpack-internal:///(action-browser)/./node_modules/@auth/core/lib/actions/callback/index.js:225:54)
    at AuthInternal (webpack-internal:///(action-browser)/./node_modules/@auth/core/lib/index.js:66:77)
    at process.processTicksAndRejections (node:internal/process/task_queues:95:5)
    at async Auth (webpack-internal:///(action-browser)/./node_modules/@auth/core/index.js:126:34)
    at async signIn (webpack-internal:///(action-browser)/./node_modules/next-auth/lib/actions.js:51:17)
    at async $$ACTION_0 (webpack-internal:///(action-browser)/./src/actions/login-action.ts:27:25)
    at async /home/hossein/programing/insurance/node_modules/next/dist/compiled/next-server/app-page.runtime.dev.js:39:418
    at async rw (/home/hossein/programing/insurance/node_modules/next/dist/compiled/next-server/app-page.runtime.dev.js:38:7978)
    at async r6 (/home/hossein/programing/insurance/node_modules/next/dist/compiled/next-server/app-page.runtime.dev.js:41:1256)```

This message it self is saying that there is an error Password is incorrect - Please check credentials
But you have to extract it in the catch block to make it usable

 if (error instanceof Error) {
      return { success: false, message: error.message };
    }

@Redbeardjunior
Copy link

Redbeardjunior commented Sep 25, 2024

when you show user does not exist or password is not correct CredentialsSignin error show up in your log server ? like this :

[auth][error] CredentialsSignin: Password is incorrect - Please check credentials
    at Object.authorize (webpack-internal:///(action-browser)/./src/config/auth.config.ts:89:23)
    at Module.callback (webpack-internal:///(action-browser)/./node_modules/@auth/core/lib/actions/callback/index.js:225:54)
    at AuthInternal (webpack-internal:///(action-browser)/./node_modules/@auth/core/lib/index.js:66:77)
    at process.processTicksAndRejections (node:internal/process/task_queues:95:5)
    at async Auth (webpack-internal:///(action-browser)/./node_modules/@auth/core/index.js:126:34)
    at async signIn (webpack-internal:///(action-browser)/./node_modules/next-auth/lib/actions.js:51:17)
    at async $$ACTION_0 (webpack-internal:///(action-browser)/./src/actions/login-action.ts:27:25)
    at async /home/hossein/programing/insurance/node_modules/next/dist/compiled/next-server/app-page.runtime.dev.js:39:418
    at async rw (/home/hossein/programing/insurance/node_modules/next/dist/compiled/next-server/app-page.runtime.dev.js:38:7978)
    at async r6 (/home/hossein/programing/insurance/node_modules/next/dist/compiled/next-server/app-page.runtime.dev.js:41:1256)```

This message it self is saying that there is an error Password is incorrect - Please check credentials But you have to extract it in the catch block to make it usable

 if (error instanceof Error) {
      return { success: false, message: error.message };
    }

understandable, but how can we get rid off it in production ... it overflows the console.

@Ali-Raza764
Copy link

Literally, I have no idea of that :)

@nextauthjs nextauthjs locked and limited conversation to collaborators Sep 25, 2024
@balazsorban44 balazsorban44 converted this issue into discussion #11910 Sep 25, 2024

This issue was moved to a discussion.

You can continue the conversation there. Go to discussion →

Labels
bug Something isn't working triage Unseen or unconfirmed by a maintainer yet. Provide extra information in the meantime.
Projects
None yet
Development

No branches or pull requests

7 participants