Closed h-rajabi closed 1 month ago
i seen this error in any project with next-auth-beta in github
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.
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)```
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.
CredentialsSignin
This did not worked for me. I'm still facing this issue, i can not return a custom error.
Same problem here. Stuck hours for this silly error.
Any solution found ?
Edit by maintainer bot: Comment was automatically minimized because it was considered unhelpful. (If you think this was by mistake, let us know). Please only comment if it adds context to the issue. If you want to express that you have the same problem, use the upvote 👍 on the issue description or subscribe to the issue for updates. Thanks!
@jhoanborges which next-auth version are you using?
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
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.
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;
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>
);
}
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 };
}
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 usableif (error instanceof Error) { return { success: false, message: error.message }; }
understandable, but how can we get rid off it in production ... it overflows the console.
Literally, I have no idea of that :)
Environment
auth.config file
my server action
and then i try to wen user can`t login
throw new Error("some error)
orthrow new AuthError("some error")
but this not work and get CallBackErrorervery 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