1

I'm making a node.js app with express and I'm trying to make a login form for my users, I want to have a Javascript file with a fetch() call to make a POST request to my API to login the user, but I can't seem to redirect the user after a successful login, it stays on the same page, I can log the result from fetch but can't redirect.

Here's the server code (authentication is working fine, just the redirect isn't):

router.post('/users/login', login.none() , async (req, res) => {
    try {
        const user = await User.findByCredentials(req.body.email, req.body.password)
        const token = await user.generateAuthToken()
        res.cookie('access_token', 'Bearer ' + token, {
            expires: new Date(Date.now() + 8 * 3600000) // cookie will be removed after 8 hours
            })
            .redirect('/users/me')
        
    } catch (error) {
        res.status(404).send()
    }
})

Here is my HTML + JS code (I know I don't need to have a function for this and can just use action="/users/login", but I want to use javascript to handle errors with the login):

<h1>Welcome</h1>
<form id="loginform" action="/users/login" method="POST">
    <input type="text" name="email" id="email" placeholder="email">
    <input type="password" name="password" id="password" placeholder="password">
    <input type="submit">
</form>
<script>
    const loginForm = document.querySelector('#loginform');
    loginForm.addEventListener('submit', (e)=> {
        e.preventDefault()
        fetch('/users/login', { method: 'POST', body: new FormData(loginForm)} )
    })
</script>
Chris
  • 18,724
  • 6
  • 46
  • 80
Gabriel Lobo
  • 162
  • 2
  • 11

3 Answers3

2

Here is my HTML + JS code (I know I don't need to have a function for this and can just use action="/users/login", but I want to use javascript to handle errors with the login):

TL;DR Use action instead of fetch(). If you need help with the error handling part, post a new question about it.

Using action for form submission and JavaScript for error handling are not mutually exclusive. The problem here is that fetch() makes an AJAX request which returns the response as a value directly in the current page. It will not automatically redirect according to the response code. You can add some additional logic to do this, but why make this more complicated than necessary.

Instead add an action attribute to your <form>:

<form name="login" id="loginform" action="/users/login/" method="POST">

Then write JavaScript to do your error handling. Only call preventDefault() when there is an error to prevent the form submission. But allow normal submission when there is no errors.

Code-Apprentice
  • 81,660
  • 23
  • 145
  • 268
  • Thank you for your answer! In my app, I'm not currently validating email/password (checking length, etc), I'm just veryfing if the credentials match with the users in the database, can I still handle that response with Javascript and form action? If so, do you know where I can learn more about this? – Gabriel Lobo Dec 22 '20 at 20:40
  • @GabrielLobo Verifying the username/password should be done on the backend. The frontend should know nothing about the database directly, so it shouldn't have access to the passwords anyway. (Aside: be sure the password are hashed in the database and not stored as plaintext.) In the case of invalid credentials, the `/users/login` route can return the form including an error message. – Code-Apprentice Dec 22 '20 at 20:56
  • @GabrielLobo Where does the initial login form come from? How will a user navigate to it? – Code-Apprentice Dec 22 '20 at 21:00
  • Yes, the verification is handled in the backend, here's what I'm trying to do: Submit form from front-end, verify email and pass in the backend, if credentials are valid, redirect the user to another page, else, stay on the same page but show an error on the form – Gabriel Lobo Dec 22 '20 at 22:53
  • @GabrielLobo You have at least two options here: 1. Use `action` as described in my answer which allows the browser to follow the redirect response returned by the Node.js backend. 2. Modify the Node.js backend to only acknowledge that the credentials are valid. It returns the cookie with the token but doesn't redirect. Then the frontend decides what to display next. – Code-Apprentice Dec 23 '20 at 16:59
  • @GabrielLobo Which of these two you decide to use depends entirely on how you wish to design your webapp and depends on my previous question: where does the intial login form come from? If this form is served directly by your Node.js backend, then #1 is appropriate. The downside is that this tightly ties your frontend and backend together. On the other hand, #2 allows a much looser connection between the frontend and backend if you design the backend correctly as some kind of API, such as REST. – Code-Apprentice Dec 23 '20 at 17:01
  • Thank you so much for your time and answers! I'll try to implement the second option next week, seeing that my back-end will be like an API. Happy hollidays! – Gabriel Lobo Dec 24 '20 at 17:08
  • @GabrielLobo In the case of an API, the backend should only return an auth token and not a redirect response. The front end is responsible for deciding what to display after recieving the response with the token. Good luck with your coding! – Code-Apprentice Dec 24 '20 at 18:55
2

You need to

  • Set the redirect option on your fetch() to manual. If you don't, the default value is follow, and fetch will follow the redirect... meaning your response body andheaders will be that of the redirect target URL, not of your original POST.

Once you do that, response.redirected will be true if the request's response status is a 301/302 redirect. If response.redirected is true,

  • set window.location to the redirect target. That should be response.url (and you should check response.useFinalURL, which, as you follow the redirect chain, should be false until you get a non-redirect status code.)

See this answer to the question redirect after a fetch post call.

Also:

So your submit event handler should look something like:

loginForm.addEventListener('submit', (e)=> {
  e.preventDefault();
  
  fetch('/users/login', {
    method: 'POST',
    redirect: 'manual',
    body: new FormData(loginForm),
  }).then( res => {

    if ( response.redirected) {
       window.location.href = response.url;
       return;
    }

    // what do you do with a non-redirect?

  }).catch ( e => {

    // handle errors here

  });

})
Nicholas Carey
  • 71,308
  • 16
  • 93
  • 135
1

After login, if we get success response then we can use 4 different ways to redirect the page in javascript.

1. Redirection using (window.location.href) of Javascript

window.location.href="http://www.google.com";

2. Redirection using replace() function

window.location.replace("http://www.google.com");

3. Redirection using window assign() function

window.location.assign("http://www.google.com");

4. Redirection using navigate function

window.navigate("dashboard.html");