Now as so often,
I prepared a little starting project for you,
but whilst you do find it attached,
and whilst you can of course use it,
and then use it as you always do,
download, extract, npm install and then npm start
whilst you can do all of that, of course.
You might want to consider building that project
on your own first.
And I'll then walk through my solution
with you in a couple of seconds,
because that would be a great practice
because that project, which I prepared here,
does actually combine all the key concepts you learned about
over the last course sections.
So building this project on your own
would be a great practice.
This project will use MongoDB,
so if you decide to follow along,
you will have to start your MongoDB server on your system.
As you'll learn it in the MongoDB sections.
And then here is what we're going to build
in this course section.
Now this might look very familiar to you.
It's basically that off demo app I showed you before,
but there are some subtle differences, and extra features,
which are included in this project here.
By the way, if you don't want to write
the styles on your own,
though, that would, of course also be a great practice.
You can, of course take just the style files
in my attachment, which you find attached to this lecture.
And then look into those files to use my styles
or to find inspiration there.
Now this project, which you can build as a practice
or which you can use just like that by using my attachment,
has the good old signup process.
And since I connect it to a brand new MongoDB database here,
I can create a new user.
And once such a user is created, we can log in.
And then here, we see some new features.
Now, unlike in the authentication section,
this project here doesn't have authorization anymore.
This admin page can be visited by every logged-in user.
So if you do want to build this on your own,
you don't need to implement authorization.
Instead, every logged-in user will see this admin page,
and here we can create new blog posts
and view all created blog posts.
Of course, this is not entirely realistic here.
Not-logged-in users should also be able to see a blog posts.
And in this demo application, that's not the case.
Only logged-in users can see blog posts down there,
as soon as we created at least one.
And then all logged-in users will be able to edit
and delete those posts.
Which of course is also not necessarily
what you typically want.
Now let me show what I mean, if I create a first post here.
This is our first post.
Then down there, we have this very basic representation
of that first post.
And we can click View & Edit to be taken to this page
where we can view and edit it in one go.
And of course, here we can edit it
and add a couple of exclamation marks, save that.
And you see it was saved.
And we can also delete blog posts here.
But again, this is only unlocked if you're logged in,
and then all logged-in users can edit all the blog posts.
I built this demo application like this,
because it's still makes for a great practice.
You can still practice all the concepts you learn about.
And the focus of this course section
will be on a different topic.
We will dive into the code base in a couple of seconds,
and analyze some issues that we might find there.
And the code base of this demo project
will already be complex enough.
If it would be any more complex,
if we would also care about
not-logged-in versus logged-in users,
diving into the main point of this course section
might simply become a bit too overwhelming,
and I don't want that.
We'll see a way more realistic project
in the next section already though,
when we built this main course project,
this online shop from the ground up.
So we will also see all the concepts come together
in a pretty realistic website there.
That's by this demo project,
this demo website here, is only partly realistic
because we'll focus on something else.
Nonetheless, you saw all the core features we have here.
And we're only using concepts you already learned about.
So again, definitely as a challenge,
don't just take the attached code.
Instead, try building this on your own.
And in a couple of seconds, which I give you
to pause the video and try building this on your own.
I will walk through my solution code together with you,
so that you can see how I built this
before we then thereafter dive into the main topic
of this course section,
which will be all about improving our code.
So did you succeed?
Let's explore to code I prepared for you together.
You can, of course now download it
so that you can follow along with exactly the same code.
Now, if we have a look at the example project I gave to you,
you will see, I have this data folder
with the database.js file as you know it.
There, I'm connecting to the auth-blog database
on my MongoDB server.
But it's the basic file you already know.
In public styles, I prepared a couple of style files
and you can simply go through that CSS code
to see what it does, but it's fairly simple CSS code,
no fancy styles in there.
Now then we got the views and the routes folders.
Let's start with the views.
There, I got a bunch of includes,
for example, all the for the post-form and the post-item,
because I'm repeating a bunch of post-items
on my admin page after some posts were added.
And I'm also using the same post-form twice
on the admin page for creating a new post,
and on the single post page when we view and edit that post.
Now, then I got a couple of other pages,
one for showing that you're not authenticated,
one if some other error occurs.
Then the admin page here,
which does include that post-form
with a bunch of data that's sent into it.
I'll come back to that data in a second.
And then here I'm rendering my list of posts,
unless I don't have any,
in which case I show a fallback message.
Then the login.ejs file, which is the same login.ejs file
I used in the authentication section,
I'm just rendering my login form here
with email and password inputs.
And then I have to sign up a page
with almost the same form,
but there, we also have to confirm email field as well,
which is why I'm not outsourcing this form into an include
because the two forms aren't exactly the same.
Then the single-post.ejs file,
if we clicked on that View & Edit button,
it basically just shows the form
with the data for this post.
And then the welcome.ejs file
which just is a home site here.
These are the EJS files I have,
the templates I have here.
So quite a few, as you can tell.
And then we've got the routes file,
the routes folder with this file here
and before we have a look at that,
of course also app.js,
in which I'm importing a bunch of third party packages,
where I then set up my session
using the MongoDB storage again.
Then I also do is set up CSRF protection,
as you learn that in the last course section.
And you will see in the routes,
we'll have a look at them in a second,
that I'm forwarding CSRF tokens everywhere.
And if you take a look at all the forms I have,
like here for managing posts,
there always is this hidden CSRF field in there.
And that includes the header with the form
for the Logout button, by the way.
This is also a form where a post request
is sent to the server.
And data for like all forms, it should come with that token.
If we don't include the token here,
logging out won't work and we'll get an error instead.
So I'm using that CSRF protection as you learned it.
And then here I have my own middleware
for checking the user authentication status
and for setting it on this locals key here on my response.
Then I register all my routes that are defined
in the blog.js file in the routes folder.
I got the default error handler, which is very basic here.
And then I started the server
once I connected to the database.
So fairly straight forward using the protection
and authentication concepts you'll learn about.
Now blog.js in the routes folder is a pretty big file
in the end here.
All zoom out a bit to bring more code onto the screen.
I do import a bunch of packages,
which are all part of package.json of course.
And then I, in the end, create my router
and I register a bunch of routes,
like the home screen.
Please note that I'm passing the CSRF token
to that home screen here.
So to this screen, even though I don't have a form
in the main part of this screen,
but of course I got my header on every screen
and there I got the Logout button,
which sits inside of a form as you learned,
and therefore, every page that includes the header,
which in turn includes that logout form,
needs to get a CSRF token.
So that, that CSRF token is available in that header,
otherwise it will fail.
That's why I'm doing it like this here,
why I'm passing my CSRF token to the welcome template.
And then I got my signup get route,
which loads that Signup page here.
And there, I then also got this session usage here
for handling input errors.
If the user did enter some invalid data,
then I'm extracting it here,
and I'm sending it back into the form,
so that if we would try to create a user
that already exists, for example,
and in my case, I already did create a user with that email,
I get this error.
That's all to something you saw before already.
And I'm using the exact same mechanism as shown there
just when I show it again.
And then I got the same logic in the login get route here,
which is used for presenting that Login page.
And there, I got the same kind of validation
you already know.
And then it got post routes for handling the post requests,
which are sent by these forms.
For example, here for signing up
where I then validate the user input.
Check whether the input is correct.
And where I then might flash some data onto my session,
so that it can be shown on that Signup page.
And I redirect and return if we have invalid input.
Then I check if we already have a user for that email,
if we do, I also return and show some error data.
And otherwise we hashed the password.
Create a new user which uses the hashed password,
and store that user in the database,
in the user's collection.
Then I redirected the login page.
We saw that get route up there.
And if that Login page form is submitted,
we make it into this post login route.
There I'm extracting the entered data.
I'm also validating that data
or I'm checking whether I found a user
for that data to be precise.
If not, I return and set some error data.
I do the same if the passwords are not equal,
which has checked with the bcrypt package,
since that lost package that was used
for creating the passwords.
And then if everything is fine, if the user did log in,
I stored that data into session,
so that we, well, can check this in the future
to find out whether a user with that session
should be authenticated.
That's what you learned in the authentication section.
And then I saved a session and once it was saved,
I redirect and I do it in this order.
And I wait until the session was saved to the database
to ensure that we only show the admin page
once the user is officially authenticated.
And once we stored that data in the session,
if we redirect to early,
the admin page, which checks the user auth status
might determine that the user is not authenticated,
even though he or she is,
and that's why we're doing it like this.
We talked about that in the authentication course section.
Now in the admin route, after checking the auth status.
And here I'm using res.locals, which is that field
that is set in my custom middleware in app.js,
once I know that the user is authenticated.
Once we checked that here in the admin get route,
I get all my posts.
Again here, we're always fetching all the posts
from everyone to simplify it as a bit.
And then I also manage some session error data here,
because if we do log in here,
this form here for creating a new post,
also of course could be tricked
because whilst I do have the required attribute and so on,
we could use the dev tools to remove that.
And then I could submit the form without entering a title.
I am tricking that front end validation.
And that's why I'm also checking the input data again
on the server,
and which I added logic for also storing the user input,
and showing this error message
if I determine on the server that
the data provided by the user is wrong.
and that's, by the way, why you should always
get into the habit of validating input on the server
because you're front and code,
the attributes you add on input fields and so on,
that can always be tricked.
You'd want to double check the input you're getting
on the server to ensure you're not storing an empty value
or anything like that.
So that's what I'm doing here.
Then I rendered the admin page,
and I'm passing the input data to it.
The input data is that error data, which I might have.
And then I also of course create my CSRF token here
because we need that on this page,
on this admin page as well.
Get the log out route here, nothing too fancy there.
I'm just resetting my session data and then I'm redirecting.
And by resetting the session data, we do log out
because we can no longer verified the authentication status.
And then I got a route for registering new posts.
So that is a route that will be triggered
if this new post form here is submitted.
And in there I am performing
that service side input validation I mentioned before.
I do then set this error data
if I find out that incorrect data was submitted,
and then if everything is all right, on the other hand,
I create a new post, which is stored in the database.
And then I redirect back to the admin page here.
We have a get route for loading a single post.
So that's the route which is triggered
if I click on View & Edit.
And there, in the end, I create my post ID
using that MongoDB object ID thing.
I then find that post by that ID in my collection,
if I don't find a post with that ID,
I rendered the 404 page.
And I also have the logic here for extracting
some error data from a session,
because of course I do have a form on this page as well.
And just as before,
this might be submitted with incorrect data.
So I want to check if I detected incorrect data before,
so that I can show the error message
or extract the error message from the session,
and then send it back to this rendered templates
to show it there.
Because for this post route,
which is triggered if that form is submitted,
in there, I do then actually validate the user input
just as I did it for creating a post.
And I flashed that onto my session,
if I do detect erroneous input,
and then I redirect back to the page.
If we make it past this check here, though,
in this post route for editing a post,
I updated that post in my database like this,
and then I redirect thereafter.
And I'm always using async await when working with MongoDB,
simply to ensure that we wait
for these asynchronous operations to finish
before we continue.
The last route I got here is this delete route
where I'm constructing my object ID, my post ID,
and I'm then deleting a post by that ID.
So that's it.
Plenty of logic in that blog.js file,
but that is the application or the website I prepared.
And now I want to talk about a couple of problems
that we have in there.