Hey guys, in this lesson we're going to be introducing you to Level 1 Authentication. 1
And we're going to be seeing how we can allow users to register and log in to our website by allowing 2
them to enter an Email and Password. 3
This is the most basic way of authenticating a user on our website, and it is also the least secure. 4
But we've got to start somewhere, so that's what we're doing. 5
If you take a look inside the course resources for this lesson, you will see a zipped file that you can 6
download and extract as usual. 7
And once you've extracted it, you should be able to open it inside VS Code, 8
and it's called 9.1 Authentication Lv.1. 9
I want you to take a look inside this folder and see that I've already created a package.json, including 10
all the pre required node NPM packages. 11
And inside the index.js is going to be our starting file. 12
As usual, we're going to start by CD'ing into this particular project folder. 13
And once we're here we're going to run npm i in order to install all of the required packages, 14
and there's not that many, 15
it's just body-parser, EJS, Express and pg for our database. 16
If any of these are new for you, then it might mean that you have skipped some modules before. 17
So when we talked about EJS or Node or Database, and it's important to know that I'm going to assume 18
that you've watched those lessons and you're comfortable with working with Postgres Database, 19
you're comfortable with working with EJS templating, Node, Express all of that because I want to cover 20
some new content in these lessons, in this module. 21
But if you have just skipped straight into this module, just be aware, it's probably not going to 22
make sense. 23
And I strongly, strongly advise you to do the entire course from beginning to end, even if you do 24
it at 2X speed and just complete all of the exercises and projects, 25
that way, at least you'll know that you're on the same level as everybody else starting this lesson. 26
So once we've run our npm install, then the next step is to go ahead and start up our server. 27
So I'm going to use Nodemon and go into our index.js. 28
And once our server is up and running on port 3000 I'm going to go over to localhost:3000, 29
and here you will see our website. 30
The website is a pretty simple bootstrapped website where we have just two buttons on the home page. 31
So this is the home page. 32
We have a Login button that takes us to a Login page, and we have a Register button that takes us to 33
a very similar looking Register page. 34
So I've tried to keep everything else super simple, just so that we can focus on the most important 35
things. 36
Now, if you look inside the views folder, you'll see that we've got our partials, we've got our home 37
page, login, register, 38
but there's also another page called secrets.ejs. 39
And this page is super simple, 40
it looks pretty much the same as the other pages, 41
it's just got an h1 and a paragraph element that has some sort of secret that the user can only access 42
once they have authenticated themselves on our website. 43
This is the page that we're trying to prevent unauthorized access to, and we're going to render it 44
only when the user has registered and logged in. 45
You'll notice in the index.js, I've already included the bare bones of this website. 46
So you should be able to simply just get it up and running. 47
But if you take a look at the routes, you'll see that the GET routes don't need any work on our part. 48
And it's also super simple, 49
just render home page, render login, render register, 50
but in the POST routes, these are the two routes that we're going to be working on in this lesson 51
in order to allow the user to POST a request to our server to register themselves and post to our server 52
to log in 53
once they've done that. If you look inside the register or the login page, they're actually exactly 54
the same 55
with respect to this, you'll see that this is the section that makes the POST request. 56
This is our form. 57
Notice the action of the form. 58
So this is the route that it's going to hit up in our server. 59
Notice that it's got a method of POST, 60
so it's going to be submitting the data from the form. 61
And that there are two inputs. 62
One has a name of username and the other one has a name of password. 63
So those are the things that we're going to have to target when we use our body-parser to grab hold 64
of the text that the user enters. 65
Now if you scroll down, you'll see some commented out code in here, 66
don't worry about that, 67
we're going to deal with this in another lesson, and we're going to try and keep this simple for now. 68
So leave all the code inside the views folder as it is, but just be aware of what the name is for each 69
of these fields so that you know how to get hold of it in the app.post(). 70
Okay, so first challenge is to go into the app.post() under the register, and the login routes, 71
and I want you to be able to console.log() whatever the user enters into the username field and the 72
password field. 73
Make sure that these lines of code work both in the register and the login routes. 74
So to do this, you're going to have to review what you learned previously regarding body-parser. 75
Now notice I've already included the app.use() for our body-parser middleware 76
and of course, as you might remember, Express already includes that, 77
so if you wanted to use the Express version of urlencoded, feel free to change this code, 78
but I recommend just to keep everything as it is and look inside the register.ejs 79
and secrets.ejs to figure out how you can console.log() 80
the username and password both on the login screen. 81
So if I was to click login, I should be able to see that console.log() down here instead of an error. 82
So at the moment it's obviously undefined. 83
But you're going to fix that very shortly. 84
So pause the video and give that a go. 85
All right, so this shouldn't be too hard. 86
All we need to do is to create a const, which in this case I've decided to call username, 87
and we're going to tap into it from req.body, 88
and then the final variable name depends on how it is 89
we named it here, 90
and notice both in register.ejs as well as login.ejs, 91
they're called username and password. 92
So that means we can say req.body.username. 93
And do the same for request.body.password. 94
And I can simply copy and paste these two lines into our login. 95
And now if we go ahead and open up the terminal down here, you should be able to see if I go back to 96
this website. 97
Go back to the login page, click the login. 98
I've already got my values prefilled, but feel free to type yours in. 99
If we go down here, you can see we've got the username and password printed out and it should work 100
exactly the same way for Register and you'll see that printed out as well. 101
You'll see that my password is pretty simple 123456, 102
and I've got the email here as well. 103
So if you managed to complete that, go ahead and delete all the console.logs, 104
and we're going to rename this from username to email. 105
Now notice not this part because this comes from the form just this part. 106
And this is helpful so that we actually can mentally differentiate which part is from the EJS form 107
and which part is going to be used in our POST request. 108
So we've got the user's email and password. 109
The next step is simply adding that into our database when they register. 110
So we're going to add the user into a new Database called users. 111
I'm going to save their email and password so that when they come back and try to log in, we're going 112
to check the password against the user with a particular email, 113
and that's basically the logic of how we can verify a user in the most simple way using our Postgres 114
database and our Node backend. 115
If at this point you feel like giving yourself a challenge because you do in fact have all the skills 116
already from our Database Section to be able to implement this, then go ahead, pause the video and 117
try and do it yourself. 118
Don't worry if it doesn't work. 119
Don't worry if you get stuck. 120
You can always come back. 121
I'm always going to be here to run through the code with you, 122
but just as an added challenge, it might be good to try it as a starting point. 123
The rest of you who are following along with me the first thing, as you can imagine that we need to 124
do is to set up our database. 125
If you look inside the file called queries.sql, in this folder, you'll see that I've already added 126
a query in here that allows us to create the table that we need. 127
It's got a ID as the primary key as usual. 128
And then we've got our email and password and I've set them as VARCHAR. 129
Email has some additional modifiers, 130
it can not be null, 131
and it has to be unique so that each user has a unique entry. 132
And I've left the password relatively easy. 133
Feel free to add any other modifiers you want based on what you've learned in the Database Section, 134
but otherwise, we're going to copy this query and go into our pgAdmin. 135
And firstly we're going to create our Database. 136
So right-click on Databases, create our database, 137
and I'm going to call it secrets. 138
And I'm going to go ahead and hit Save. 139
Now I have my database called secrets. 140
I'm going to click on the Query Tool to be able to paste in the query that I want to run, which creates 141
a table called users inside that database with these three simple fields. 142
Now, let's hit Run and hopefully, you'll have query returned successfully. 143
So now if we take a look inside that database, inside Schemas, inside Tables, and you go ahead and click 144
Refresh, you should see that we now have a users table, 145
and we're going to view all rows 146
and you'll see that right now we just have an empty header. 147
This is where we're going to be entering our users details 148
when they register. We're going to save their email, save their password, 149
the ID is auto generated, 150
and we'll be able to use it later on when we need to check them when they log in. 151
Coming back to our index.js, the first thing we need to do in order to connect to that database that 152
we just created is to, import pg from "pg". 153
So that was the module that has already been installed from our package.json. 154
And this allows us to work with our Postgres database from Node. 155
And then the next thing we're going to do is we're going to connect to that database. 156
This is the code that we usually use, 157
and remember I named my database "secrets" 158
as you can see right here. I gave my database a starting password of "123456" which was created long ago 159
when we set up Postgres. 160
My username is "postgres" and the 161
host is "localhost". 162
And again, we've explained all of this to great lengths and in great detail in the Database Section. 163
So I'm not going to talk about this anymore other than the fact that we are now creating a new database 164
connection and then we connect to it, and once we have done that, then we are ready to start registering 165
some users. 166
We know that we can get hold of their email and their password through these two constants, 167
can you figure out how to insert the email and password into our users' table using a PostgreSQL query? 168
And once that's done, then go ahead and res.render the secrets.ejs. 169
Pause the video and give that a go. 170
All right. 171
So this is what the code should look like. 172
We are making a database query which has this particular SQL code, we're inserting into our table called 173
users, 174
and the values that we're inserting is email and password which corresponds to the values, $1, $2 175
which is inserted here as an array. 176
You can go ahead and console.log() the result to see if it was successful or what happens, 177
but in most cases, it should work and we should be able to simply go ahead and res.render our secrets.ejs 178
. 179
Let's go ahead and try that out for real. 180
Let's try and register this user, angela@gmail.com with my password, 181
and you can see that, firstly I get taken to the secret.ejs file showing the secret page, 182
but also if I go into my pgAdmin and I right-click and View my users, you'll see that I have a new 183
row of data corresponding to what it is I just inserted. 184
Now, 185
there's a bit of a problem here though, because what if we tried to register a user that already exists? 186
Because right now if I click register, I'm going to get an error 187
and if I go back to my file, you'll see that the error is because I'm trying to insert a row that has 188
a duplicate key value, because we have a unique constraint on the email field, which you might remember 189
from this line here has to be not null and it has to be unique. 190
So by trying to insert the same email in a different record in that table, I end up tripping this. 191
And this is quite an important one for us to trip. 192
It's not wrong that that happens. 193
It just means that we need to handle it. 194
So how do we handle it? 195
Well, I'm going to wrap this inside an if statement. 196
So instead of simply just straight up inserting, I'm going to first check to see if I already have 197
that user in my users table. 198
So, "SELECT * FROM users WHERE email = $1", 199
email is of course the one that they entered in the field. 200
And then if the checkResult.rows .length, if that result comes back with a value, then that means 201
I already have a user with that email. 202
So I can simply do something like res.send or render a different page, or create a little pop-up or 203
a little message, something that I can handle on the front end to tell the user, "Hey, you're already 204
registered. 205
Maybe you can try logging in." 206
An alternative flow that you can consider when you're making a more complex website is you can simply 207
just log them in yourself using a code by taking their email and password. 208
But the important thing here is we first check, 209
and if they already exist, we perform some sort of action. 210
If they don't exist, then we insert them into our database. 211
And that unique constraint is quite important so that we don't end up doubling up on users with the 212
same email, but different passwords because they try to register multiple times. 213
That is something to be aware of and this code will catch that out. 214
One final thing I recommend doing is actually wrapping all of the queries inside a try and catch block. 215
And the reason for this is because whenever we're working with pg, things might not work, we might 216
not be connected to the database, or we might have lost connection, or the database might be gone, 217
or it might not be at the right address, or it might not have the right password, 218
but it's a good idea to try and catch these. 219
And if there are any errors to either console.log() them or to handle them appropriately. 220
That concludes the entire section we need to do to register a user. 221
The next part is figuring out how we can check when a user enters their email and password, 222
check them against our database. 223
So find the user with this email, see if they exist, and if they don't exist, then we tell them, "You 224
haven't registered," 225
but if they do exist, then we check their password that they entered here in the form against the one 226
that we had saved in our database. 227
They match, 228
we let them go through to see the secrets page, and if it doesn't match, then we tell them it doesn't 229
match. 230
So see if you can use what you've learned about Postgres Databases in previous modules to complete this 231
functionality. 232
Thinking about what we talked about in the register route, such as the try catch, such as checking 233
the result, whether if it exists, etc. So pause the video. 234
Give this a go. 235
All right. 236
So let's run through the solution code. 237
First thing we do is we wrap everything inside a try catch block, 238
then we make our database query. 239
The first query is we're going to select everything from the users table where the email is a match 240
for the one that was entered in the form. 241
Now once we get the result back, if there is a result, if the user does in fact exist in our database, 242
then that means they have previously registered in our database. 243
So that means that the result.rows[0] should contain all of the data of that user. 244
And in fact you can actually simply verify this by console logging that. 245
So if I console.log(result.rows) and hit Save, go to the login route which is where we've got our 246
console.log(), 247
try to enter that email and password, 248
go back over here and check what gets printed out. 249
You can see that it's an array and there's only one row that matches that criteria, 250
because of course the emails are unique, 251
and the first element in that array is the object that contains the ID, the email, and the password 252
of that user. 253
So what that means is we can then set the user to result.rows[0] 254
and that is going to be equivalent to this object right here. 255
And then we can set the stored password, so the password on our database to user.password. 256
Finally, all we need to do is check if the password which is the entered password matches the stored 257
password 258
and if it does, we're going to res.render(secrets ejs), 259
otherwise we're going to tell them, "Incorrect password", 260
or we're going to redirect them back to login 261
or we're going to give them a flash message, whatever it is you want to do. 262
But this should be handled separately. 263
And also this other else statement is here because it catches the cases where result.rows.length 264
is 0, which means that no user was actually found in our database using this email. 265
That means that the user is not found, which could mean they're not registered or they registered with 266
a different email, 267
but either way, you want to handle that by telling the user what is going on. 268
There you have it. 269
We now have a login route and a register route. 270
We save our user's email and password into our database. 271
We check their saved password against the password they enter when they try to log in, and if the passwords 272
match, then we show them the secret page. 273
This is not bad because it works, but it's also not great because you can see the user's password right 274
there in plain text in our database. 275
So that means that if somebody hacks into the database, if somebody manages to get this data, then 276
every user's password is matched against their email, and this bad person will be able to know that 277
user's email, 278
and they might use that email across multiple websites on the internet, 279
and it could be a really bad thing for them. 280
So this, while it works and it is the most basic level of authentication, is not enough. 281
So in the next lesson, we're going to cover the next Level of authentication where we talk about encryption, 282
salting, hashing, passwords, all of the important things that makes this more secure for our users. 283
So for all of that and more, I'll see you on the next lesson.