Bootcamp
Search…
3.5.2: User Auth

Introduction

All of us have lots of experience using user login on websites we use every day. We'll talk about how to implement it in our app, using a users table and cookies.
The logic for user login is:
  1. 1.
    The user registers by giving us a unique identifier and password. Common unique identifiers are emails and usernames. Only one user in the system can have this identifier.
  2. 2.
    The user signs in. They enter their unique identifier and their password. The server receives the identifier and password. If both attributes match what is in the system, then the user is "authenticated".
In our app, the flow will go like this:
  1. 1.
    User makes a GET request to render a register form.
  2. 2.
    The user fills out the register form and submits it.
  3. 3.
    The web app saves their email and password.
  4. 4.
    (Some time in the future) the user makes a GET request to a sign in form.
  5. 5.
    The user fills out the form with the same info they registered with and submits it.
  6. 6.
    The web app receives the request and checks in the database to see if it has matching info.
  7. 7.
    If the info matches, send back a cookie to the user.
  8. 8.
    The browser stores this "log in" cookie.
  9. 9.
    (Some time in the future) the user makes a request to a login-only page like/account
  10. 10.
    The web app receives the request and evaluates the cookie to see if the requesting user is allowed access to the page.
  11. 11.
    If the user is not allowed, send back a status 403. 403 represents "forbidden".
  12. 12.
    If the user is allowed, render the page.
Note that our system relies on the fact that the user's email is unique in the system.
The signup functionality has to verify that the user's email is unique before putting the user record into the database.

Users Table Definition

Here is a sample CREATE TABLE query for the users table. In practice, we NEVER want to store passwords in plain text, but we are doing that here for demonstration.
1
CREATE TABLE users (id SERIAL PRIMARY KEY, email TEXT, password TEXT);
Copied!

Routes

The following types of routes will be necessary to create user login functionality as described above.
URL Path
Method
Purpose
/signup
GET
Render a form that will sign up a user.
/signup
POST
Accept a POST request to create a user.
/login
GET
Render a form that will log a user in.
/login
POST
Accept a POST request to log a user in.
/logout
DELETE
Log a user out. Get rid of their cookie.

Auth Logic in Express

Login Form

HTML input fields of type "password" allow users to enter hidden text. More info on password input fields here.
1
<form action="/login" method="POST">
2
<input type="text" name="email" />
3
<input type="password" name="password" />
4
<input type="submit" value="Submit">
5
</form>
Copied!

index.js

1
app.post('/login', (request, response) => {
2
console.log('request came in');
3
​
4
const values = [request.body.email];
5
​
6
pool.query('SELECT * from users WHERE email=$1', values, (error, result) => {
7
if (error) {
8
console.log('Error executing query', error.stack);
9
response.status(503).send(result.rows);
10
return;
11
}
12
​
13
if (result.rows.length === 0) {
14
// we didnt find a user with that email.
15
// the error for password and user are the same. don't tell the user which error they got for security reasons, otherwise people can guess if a person is a user of a given service.
16
response.status(403).send('sorry!');
17
return;
18
}
19
​
20
const user = result.rows[0];
21
​
22
if (user.password === request.body.password) {
23
response.cookie('loggedIn', true);
24
response.send('logged in!');
25
} else {
26
// password didn't match
27
// the error for password and user are the same. don't tell the user which error they got for security reasons, otherwise people can guess if a person is a user of a given service.
28
response.status(403).send("sorry!");
29
}
30
});
31
});
Copied!
The URL path /user-dashboard is fictitious, used to represent a path that requires authentication to visit.
1
app.get('/user-dashboard', (request, response) => {
2
if (request.cookies.loggedIn === undefined) {
3
response.status(403).send('sorry, please log in!');
4
return;
5
}
6
// ...
7
});
Copied!

Security Flaws

There are a number of security flaws with the above implementation that we will address in upcoming modules.
  1. 1.
    If using HTTP instead of HTTPS, passwords are sent in plain-text, rendering them insecure.
  2. 2.
    Passwords are stored in plain text in the database. This is dangerous because any hackers to the database would have access to all passwords.
  3. 3.
    The auth cookie loggedIn can be faked by anyone by setting that cookie manually in their browser.
  4. 4.
    There is no mechanism to prevent brute-force guessing of passwords.
  5. 5.
    There is no input validation to prevent SQL injection attacks.