Let’s now implement login!

It’s going to be very similar to the registration, except we call /api/auth/login, and we don’t have to handle the password confirmation. And contrary to registration, we fail if the user is not there yet.

Here is the endpoint we add in the server.js file:

server.post('/api/auth/login', async (req, res) => {
  passport.authenticate('local', (err, user, info) => {
    if (err) {
      res.statusCode = 500
      res.end(
        JSON.stringify({
          status: 'error',
          message: err
        })
      )
      return
    }

    if (!user) {
      res.statusCode = 500
      res.end(
        JSON.stringify({
          status: 'error',
          message: 'No user matching credentials'
        })
      )
      return
    }

    req.login(user, err => {
      if (err) {
        res.statusCode = 500
        res.end(
          JSON.stringify({
            status: 'error',
            message: err
          })
        )
        return
      }

      return res.end(
        JSON.stringify({
          status: 'success',
          message: 'Logged in'
        })
      )
    })
  })(req, res, next)
})

As you can see, we also call the req.login() method to log in the user, and we send the successful response back (or an error if something wrong happens).

We call this from the components/LoginModal.js component.

Right now we have this content in that file:

components/LoginModal.js

export default props => (
  <>
    <h2>Log in</h2>
    <div>
      <form
        onSubmit={event => {
          alert('Log in!')
          event.preventDefault()
        }}>
        <input id='email' type='email' placeholder='Email address' />
        <input id='password' type='password' placeholder='Password' />
        <button>Log in</button>
      </form>
      <p>
        Don't have an account yet?{' '}
        <a href='#' onClick={() => props.showSignup()}>
          Sign up
        </a>
      </p>
    </div>
  </>
)

I’m going to copy most the content of the components/RegistrationModal.js file in here, except we don’t have a password confirmation, and we do a POST request to /api/auth/login:

import { useState } from 'react'
import axios from 'axios'
import { useStoreActions } from 'easy-peasy'

export default props => {
  const [email, setEmail] = useState('')
  const [password, setPassword] = useState('')
  const setUser = useStoreActions(actions => actions.user.setUser)
  const setHideModal = useStoreActions(actions => actions.modals.setHideModal)

  return (
    <>
      <h2>Sign up</h2>
      <div>
        <form
          onSubmit={async event => {
            try {
              const response = await axios.post('/api/auth/login', { email, password })
              if (response.data.status === 'error') {
                alert(response.data.message)
                return
              }
              setUser(email)
              setHideModal()
            } catch (error) {
              alert(error.response.data.message)
              return
            }
            event.preventDefault()
          }}>
          <input
            id='email'
            type='email'
            placeholder='Email address'
            onChange={event => setEmail(event.target.value)}
          />
          <input
            id='password'
            type='password'
            placeholder='Password'
            onChange={event => setPassword(event.target.value)}
          />
          <button>Log in</button>
        </form>
        <p>
          Don't have an account yet?{' '}
          <a href='#' onClick={() => props.showSignup()}>
            Sign up
          </a>
        </p>
      </div>
    </>
  )
}

That’s it!

Try the application: you should be able to create a new user using the registration form, log out and then log in again. If you use the wrong password, it should give you an error.

The code for this module is available at https://github.com/flaviocopes/airbnb-clone-react-nextjs/commit/e71ec89a3b8a39c2197b38124b17d5afd321e652


Go to the next module