0

I added Next-Auth's Email provider to my app, and having issues with catching signIn errors in the client. According to documentation as well as this answer, when using signIn with 'redirect: false' it will return a Promise, that resolves to the following:

{
  error: string | undefined;
  status: number;
  ok: boolean;
  url: string | null;
}

In case of errors, however, the 'error' property of the response object has only 'EmailSignin' value, and contains no other information about the kind of error. Instead, more detailed errors are printed in the terminal.

enter image description here

I have the following basic setup:

[...nextauth].js

EmailProvider({
  name: "Email",
  server: {
    host: "smtp.gmail.com",
    port: "587",
    auth: {
      user: "myusername",
      pass: "mypassword",
    },
  },
  from: "My App",
}),

And the code of my custom sign in form (modal window):

const handleSignInClick = async () => {
  const { email } = formData;
  const response = await signIn("email", {
    redirect: false,
    email,
  });
  ...
  ...
  ...
};

Is there any way to catch the errors that are printing in the console, and send them to client instead?

Ahmed Sbai
  • 10,695
  • 9
  • 19
  • 38
egurb
  • 1,176
  • 2
  • 14
  • 40

1 Answers1

1

Ok, after playing a little bit with the code + additional reading of the documentation I came up with a solution.

Basically, when you add normalizeIdentifier method to EmailProvider, it overrides the default normalization mechanism. In the method I return 'identifier' without any changes. This stops Next-Auth's logger from throwing 'invalid email' errors to the console. Here is the code:

'normalizeIdentifier' method

   EmailProvider({
    name: "Email",
    server: {
      host: "smtp.gmail.com",
      port: "587",
      auth: {
        user: "myusername",
        pass: "mypassword",
      },
    },
    from: "My App",
    normalizeIdentifier(identifier) {
      // return indentifier as is, to avoid next auth logger to log failure for invalid email
      return identifier;
    },
   })

In addition to that, I added 'signIn' callback. Which as per documentation runs 2 times. First when verification request is sent, and second after a user has clicked on a sign-in link. In the first run, you can check 'verificationRequest' which will be 'true'. And here you can do validation of the email, as well and throw an error (which will be sent to client).

'signIn' callback

 callbacks: {
   async signIn({ user: { email }, email: { verificationRequest } }) {
     if (verificationRequest) {
       try {
         // validate email here
         validateEmail(email);
       } catch {
         //thrown error will be sent to client
         throw "Email is invalid";
       }
     }
   },
 },

Here is response for invalid request:

{
    "error": "Email is invalid",
    "status": 200,
    "ok": true,
    "url": null
}

NOTE: There is only one case in which this solution will not work, and it is when email is not provided at all (normalizeIdentifier and signIn will not be triggered). So default 'EmailSignin' error is sent to client. IMO this is still OK, because logger does not pollute the console, and you know that if it's not a custom error, then there was no email provided.

egurb
  • 1,176
  • 2
  • 14
  • 40