Having trouble with Next-Auth's signIn with Credentials feature in NextJS?

I have recently added the next-auth package to my new Next.js project. Despite following all the documentation for both Next.js and next-auth, I am still unable to resolve the issue.

The problem I am encountering is as follows: I am trying to log in to my Next.js application using an Email & Password combination submitted to my API Server built on Laravel. Upon submitting the login form, I am running the function below:

import { signIn } from "next-auth/client";

const loginHandler = async (event) => {
    event.preventDefault();

    const enteredEmail = emailInputRef.current.value;
    const enteredPassword = passwordInputRef.current.value;

    const result = await signIn("credentials", {
        redirect: false,
        email: enteredEmail,
        password: enteredPassword,
    });

    console.log("finished signIn call");
    console.log(result);
};

The code snippet shown below is present in my pages/api/auth/[...nextauth].js:

import axios from "axios";
import NextAuth from "next-auth";
import Providers from "next-auth/providers";

export default NextAuth({
    session: {
        jwt: true,
    },
    providers: [
        Providers.Credentials({
          async authorize(credentials) {
            axios
              .post("MY_LOGIN_API", {
                email: credentials.email,
                password: credentials.password,
              })
              .then(function (response) {
                console.log(response);
                return true;
              })
              .catch(function (error) {
                console.log(error);
                throw new Error('I will handle this later!');
              });
          },
        }),
    ],
});

However, when attempting to log in with valid/invalid credentials, I receive the following error in Google Chrome's console log:

POST http://localhost:3000/api/auth/callback/credentials? 401 (Unauthorized)
{error: "CredentialsSignin", status: 401, ok: false, url: null}

Is there something that I might be overlooking here?

Answer №1

According to the information provided (https://next-auth.js.org/providers/credentials#example)

async authorize(credentials, req) {
  // Implement your custom logic here to retrieve user data based on the credentials
  const user = { id: 1, name: 'John Doe', email: '<a href="/cdn-cgi/l/email-protection" class="__cf_email__" data-cfemail="acb8b7afb9aae4bbbdb988b5bfb3cbacbb">[email protected]</a>' }

  if (user) {
    // Any object returned will be stored in the JWT's `user` property
    return user
  } else {
    // Return null or false to reject the credentials
    return null
    // You can also trigger an Error or specify a URL for rejection:
    // throw new Error('error message') // Redirect to error page
    // throw '/path/to/redirect'        // Redirect to a URL
  }
}

Ensure that you are returning either a user object or null from the authorize callback.

Answer №2

shanewwarren's initial answer is accurate, but allow me to provide a more detailed explanation:

To tackle this issue, we can utilize the axios library.

 async authorize(credentials, req) {
        return axios
          .post(`${process.env.NEXT_PUBLIC_STRAPI_API}/auth/login`, {
            identifier: credentials.identifier,
            password: credentials.password,
          })
          .then((response) => {
            return response.data;
          })
          .catch((error) => {
            console.log(error.response);
            throw new Error(error.response.data.message);
          }) || null;
      },

Answer №3

Consider including a try/catch block within the async function authorize(credentials) {} to handle errors more effectively. In my experience, adding some logging statements was instrumental in troubleshooting an issue that ultimately required switching to a different Node.js version.

Answer №4

I encountered the same error, but found a solution that worked:

export const authOptions = {
  secret: process.env.SECRET,
  adapter: MongoDBAdapter(clientPromise),
  providers: [
    GoogleProvider({
      clientId: process.env.GOOGLE_CLIENT_ID,
      clientSecret: process.env.GOOGLE_CLIENT_SECRET,
    }),
    CredentialsProvider({
      name: 'Credentials',
      id: 'credentials',
      credentials: {
        username: { label: "Email", type: "email", placeholder: "<a href="/cdn-cgi/l/email-protection" class="__cf_email__" data-cfemail="5b2f3e282f1b3e233a362b373e75383436">[email protected]</a>" },
        password: { label: "Password", type: "password" },
      },
      async authorize(credentials, req) {
        // const user1 = { id: 1, name: 'J Smith', email: '<a href="/cdn-cgi/l/email-protection" class="__cf_email__" data-cfemail="600a130d091408200518010d100c054e030f0d">[email protected]</a>' }
        const email = credentials?.email;
        const password = credentials?.password;

        mongoose.connect(process.env.MONGO_URL);
        const user = await User.findOne({email});
        const passwordOk = user && bcrypt.compareSync(password, user.password);
        // if (user1) {
        //   return user1;
        // }
        if (passwordOk) {
          return user;
        }

        return null
      }
    })
  ],
  session: {
    strategy: 'jwt'
  },
  secret: process.env.SECRET,
  // callbacks: {
  //   async jwt(token, user) {
  //     if (user) {
  //       console.log(user, "user jwt");
  //       token.id = user.id;
  //       token.name = user.name;
  //     }
  //     console.log(token,"token jwt");
  //     return token;
  //   },
  // },
  // callbacks: {
  //   async session(session, token) {
  //     // if you need to add more info in session
  //     console.log(token,"token session");
  //     session.user.id = token.id;
  //     session.user.name = token.name;
  //     console.log(session,"session");
  //     return session;
  //   },
  // },
};
const handler = NextAuth(authOptions);

export { handler as GET, handler as POST }

Login:

"use client";
import { signIn } from "next-auth/react";
import Image from "next/image";
import { useState } from "react";

export default function LoginPage() {
  const [email, setEmail] = useState("");
  const [password, setPassword] = useState("");
  const [loginInProgress, setLoginInProgress] = useState(false);

  async function handleFormSubmit(ev) {
    ev.preventDefault();
    setLoginInProgress(true);

    await signIn("credentials", { email, password, callbackUrl: "/" });

    setLoginInProgress(false);
  }
  return (
    <section className="mt-8">
      <h3 className="text-center text-primary font-extrabold text-4xl mb-4">
        Login
      </h3>
      <form className="max-w-xs mx-auto" onSubmit={handleFormSubmit}>
        <input type="email" name="email" placeholder="email" value={email}
               disabled={loginInProgress}
               onChange={ev => setEmail(ev.target.value)} />
        <input type="password" name="password" placeholder="password" value={password}
               disabled={loginInProgress}
               onChange={ev => setPassword(ev.target.value)}/>
        <button disabled={loginInProgress} type="submit">Login</button>
      </form>
    <hr className="mt-6"/>
      <div className="max-w-xs mx-auto">
        <div className="my-4 text-center text-gray-500">
          login with provider
        </div>
        <button
          type="button"
          onClick={() => signIn("google", { callbackUrl: "/" })}
          className="flex gap-4 justify-center"
        >
          <Image src={"/google.png"} alt={""} width={24} height={24} />
          Login with google
        </button>
      </div>
    </section>
  );
}

Answer №5

Dealing with a similar issue, I encountered some challenges.

To resolve it, I included a `try/catch` block in my fetch request and utilized a console.log() statement within the catch block to track errors effectively.

In my case, the root cause of the problem stemmed from a

self-signed certificate

To address this issue, I implemented NODE_TLS_REJECT_UNAUTHORIZED=0 in my .env.local file, efficiently resolving the error.

Answer №6

import type { NextAuthConfig } from "next-auth";
import Credentials from "next-auth/providers/credentials";
import axios from "axios";

export default {
  providers: [
    Credentials({
      credentials: {
        email: {},
        password: {},
      },
      authorize: async (credentials) => {
        let userInfo = null;

        userInfo = await axios.post("https://fakejson.com/auth/login", {
          email: credentials.email,
          password: credentials.password,
        });

        if (userInfo) {
          return userInfo.data;
        }

        return null;
      },
    }),
  ],
} meets requirements of NextAuthConfig;

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

Utilizing jQuery.post to generate a dynamic dropdown menu

I recently designed a dropdown list that functions well on a standalone page. However, I encountered an issue when attempting to display it in a table on another page using jQuery.post(). The contents appear to overflow from the dropdown list. The jQuery ...

The value of the bound variable in ng-options does not get updated after the array is

I have a situation where I am populating a list using an array and the ng-options directive in AngularJS. The selected item is bound to a variable called myObject.selectedItem. However, I noticed that even after clearing the array, the value of myObject.se ...

How to smoothly glide to the bottom of a chat box by scrolling synchronously

I am currently in the process of developing a chat application. Each time a user sends a new message, it is added to a list of messages displayed in an unordered list (ul). I have successfully made the ul scrollable, but unfortunately, when a new message i ...

Should the useRouter pathname be accessed in multiple components or passed as a prop for optimal Next.js performance?

Imagine a scenario where there is a Layout containing NavMobile and NavDtop components, each displaying based on screen size. In order to disable the link to the current page, both components require the current pathname from next/router. const router = us ...

Is it possible for a property to be null or undefined on class instances?

Consider this TypeScript interface: export interface Person { phone?: number; name?: string; } Does having the question mark next to properties in the interface mean that the name property in instances of classes implementing the interface ca ...

JavaScript - Unable to unselect a button without triggering a page refresh

I have a series of buttons in a row that I can select individually. However, I only want to be able to choose one button at a time. Every time I deselect the previously selected button, it causes the page to reload when all I really want is for all the but ...

Executing an ajax post when a user clicks on a link or button

<tr> <td> <span id="id_1"> <a href="/Path" >Name</a> <a href="#">Delete</a> </span> </td> &l ...

Double Marker Challenge in Brochure

I am currently using Leaflet in conjunction with VueJs. I have encountered an issue where a double marker is appearing at a specific location when I add a marker: The code responsible for this behavior is as follows: mounted() { this.map = L.ma ...

Enhancing Chat: Updating Chat Messages in Real-Time with Ember.js and Firebase

I recently started working with ember.js and firebase. Right now, I have successfully implemented a feature to post messages and view them in a list format as shown below: //templates/show-messages.hbs {{page-title "ShowMessages"}} <div clas ...

How can the callback from C++ be successfully installed in the Javaobject window within QtWebkit?

I have successfully implemented HTML-JS to call a C++ method using QtWebkit. Now, I want to send a callback from the C++ method to the JavaScript window. How can I achieve this? Below is my code snippet. #include <QtGui/QApplication> #include <Q ...

The function $(...) does not recognize tablesorter

Currently, I am encountering issues with the tablesorter plugin as my system is unable to recognize the existing function. It is unclear whether there might be a conflict with other JavaScript files, especially since I am implementing changes within a Word ...

Error: Unable to access 'push' property of null object in Next.js Link

Utilizing Vite to develop a reusable component has led to an error upon publishing and reusing it: TypeError: Cannot read properties of null (reading 'push') The code for the component is as follows: import React from "react"; import ...

The functionality of "exportTrailingSlash: true" is not performing as intended, causing links to not properly redirect to the

I am currently working with nextjs and attempting to perform a static export. My configuration in the next.config.js file is as follows: module.export = { exportTrailingSlash: true, } During development, I write links without the suffix. For example, ...

Is there a way to establish a connection with a secondary Firestore database in Node.js, allowing for the use of multiple Firestore databases

I have set up multiple firestore databases within my project. Using the command line, I created these databases and can view them in the Firestore Databases preview by following the instructions outlined here: https://cloud.google.com/blog/products/databas ...

Display numerous occurrences of a certain class by utilizing a different class

I'm currently in the process of creating a board game similar to Ludo, which requires a grid of 13x13 squares. I've created a Box class that successfully renders a single square button. Here's the code: class Box extends React.Component{ r ...

Dropping challenging shapes in a block-matching game similar to Tetris

I'm currently working on a game similar to Tetris, but with a twist. Instead of removing just one line when it's full, I want to remove all connected pieces at once. However, I've run into a roadblock when trying to implement the hard-drop f ...

Can a <Link> be customized with a specific condition?

On the webpage, there is a list of elements retrieved from a database. When clicking on the last displayed element, I want to link to '/upload' if it shows "Carica Referto", or link to '/consensi/{this.$state.item.hash_consenso}' if it ...

Designing an interactive HTML table that adapts to various screen

Currently utilizing Bootstrap to create a responsive HTML table on smaller devices like the iPad, but seeking a more polished and professional alternative. Searching for a JQuery/JavaScript or CSS solution without relying on plugins. Would appreciate any ...

JavaScript throws an error when attempting to access an object's methods and attributes

Within my Angular.js module, I have defined an object like this: $scope.Stack = function () { this.top = null; this.size = 0; }; However, when I try to use the push method of this object, I encounter an error stating undefined: ...

Post-render for HTML linkage

Is there a method to execute customized code after Knockout has inserted the html into the DOM and completed rendering? This is required in order to bind a nested view model to dynamically generated html code. Perhaps like this: <div data-bind="html: ...