failed login redirects me to /api/auth/error on next-auth

6.6k views Asked by At

I'm using next-auth v. 4.18.8 in my login page. This is the final project of my Fullstack JS course. I'm using a newer version than the one used in the course (next-auth v. 3 is used)

When I insert the correct password, everything works as it should (it redirects me to the desired page).

Inserting the wrong password should throw me to /auth/signin?i=1 so I can handle this query. However, it redirects me to http://127.0.0.1:3000/api/auth/error?error=Request%20failed%20with%20status%20code%20401

On console, it shows "POST http://localhost:3000/api/auth/callback/credentials? 401 (Unauthorized)"

Here's my code:

Frontend: Login Page

  const handleFormSubmit = async values => {
    signIn('credentials', {
     email: values.email,
     password: values.password,
     callbackUrl: 'http://127.0.0.1:3000/user/dashboard'
    })
 }

Frontend: [...nextauth].js

export const authOptions = {
  providers: [
    CredentialsProvider({
        name: 'credentials',
        async authorize(credentials, req) {
            const res = await axios.post('http://127.0.0.1:3000/api/auth/signin', credentials)

            const user = res.data

            if (user) {
                return user
            } else {
                throw '/auth/signin?i=1'
            }
          }
    })
  ],

  session: {
    jwt: true
  }, 

  jwt: {
    secret: process.env.JWT_TOKEN
  },

  adapter: MongooseAdapter(process.env.MONGODB_URI)
}
export default NextAuth(authOptions)

Backend: signin.js controller

const authSignin = {

    post: async (req, res) => {
        const {
            name,
            email,
            password,
          } = req.body

          await dbConnect()
          
          const user = await UsersModel.findOne({ email })

          if (!user) {
            return res.status(401).json({ success: false, message: "invalid" })
          }

          const passIsCorrect = await compare(password, user.password)

          if (passIsCorrect) {
            return res.status(200).json({
              _id: user._id,
              name: user.name,
              email: user.email
            })
          }
        
          
          return res.status(401).json({ success: false, message: "invalid" })
 
        }
}

export { authSignin }

Finally: Backend: signin.js routes (using Next Connect):


import nextConnect from 'next-connect'

import { authSignin } from '../../../src/controllers/auth/signin'
 
const route = nextConnect()

route.post(authSignin.post)

export default route

One thing I noticed is that when inserting a wrong password, when the code reaches this line on controller:

return res.status(401).json({ success: false, message: "invalid" })

It wont continue to execute the [...nextauth].js file after axios.post, therefore not executing the code below, which should give me the 'i' query to handle on frontend (as stated in next-auth documentation):

if (user) {
   return user
} else {
   throw '/auth/signin?i=1'
}

The repository is on GitHub

1

There are 1 answers

0
Yilmaz On BEST ANSWER

I think if you pass redirect:false here

const handleFormSubmit = async values => {
    signIn('credentials', {
     email: values.email,
     password: values.password,
     callbackUrl: 'http://127.0.0.1:3000/user/dashboard',
     redirect: false,
    })
 }

Looks like when next-auth encounters an error, it automatically redirects. By setting the redirect option it will not automatically redirect so you could handle the error on client side like this

  const handleFormSubmit = async values => {
       const signInResult=signIn('credentials', {
         email: values.email,
         password: values.password,
         callbackUrl: 'http://127.0.0.1:3000/user/dashboard',
         redirect: false,
       })
       If (signInResult.error){
           // Handle Error on client side
       }
      
     }

Also you should not make api request in authorize. it will delay the process. you could run the signin logic inside the authorize