- [Maximilian] So now to find out
whether we want to grant access or not,
in this admin get route,
we have to look into the session
of an incoming request,
and see whether that request
does have a session to begin with,
and then B, if in the session data
for this client, so for that session ID
that's submitted by the client,
we actually do have this authentication data.
Because if we only got some other data
in the session, that's nice to have,
but that still won't grant access here.
So the existence of a session alone is not enough
because, as mentioned before,
sessions are also created
for unauthenticated users.
So it's really the authentication data in the session
that matters to us here.
That's the actual ticket.
Or to stay in the analogy,
that's the content of the ticket
that matters to us.
So here, in this get route, in this get admin route,
I will simply check if not
request.session.isAuthenticated,
if that is false or falsy.
Because remember, I'm setting isAuthenticated here to true
and therefore, if this is false or doesn't exist,
in which case it's treated as falsy statement,
so if this is not true or truthy,
then we know the user is not authenticated.
Alternatively, if we didn't store
this extra isAuthenticated flag,
we could also check if not request.session.user,
if this user object doesn't exist.
Because we know this will only exist
if the user did log in,
because that's the only place
where we set it.
And we will soon delete it
whenever our user logs out, for example.
We haven't added that functionality yet,
but we will soon do so.
So if the user is not authenticated here,
then I will return
so that this code down there
doesn't execute.
And I'll return the rendered 401 template,
which is that template I prepared
for the "You are not authenticated" case.
And I'll not just render that.
I'll also set the status code to 401,
because that is the typical status code
you do use for signaling that access was denied.
It's not technically necessary to set this code,
but it's a bit more correct
to not just show the user this error page,
but to also make it clear to the browser
and so on that this page is shown
because the user tried to access
some page where authentication was denied.
So that's what we do if we don't find
the isAuthenticated flag.
And hence now, if we save all that code
and we go back to our website,
if I now try to go to admin,
I'm not authenticated.
I see this "Not authenticated" page,
because at this point I don't have this session
with the auth-data yet.
I didn't log in yet
since we added this session code.
I also want to show you one other interesting thing.
If you open the developer tools,
you can go to the application tab there,
and there you have a cookies area.
Here.
Here you can see all the cookies
the browser is storing for a given website.
And for most websites,
you will see a lot of cookies there
because they have tracking cookies
or advertisement cookies,
or because they're using some integrated services
that might set their own cookies.
Here for this page,
if you navigate around on the different pages,
you typically shouldn't see a cookie
at this point here.
You shouldn't have a cookie here for this page.
If you do have some cookies here,
try visiting this page in an incognito tab.
So you shouldn't have any cookies yet,
and you especially shouldn't have
any session-related cookie yet.
Because we haven't done anything
that would add data to the session,
and we did configure our session
to only be saved to the database
if data was added,
because saveUninitialized was set to false,
so an empty session with no data inside
won't be stored to the database,
and hence no session cookie will be generated.
But if I now go to the login page here
and there, I do log in
with my valid credentials
and I click Login here,
you will notice a couple of things.
You will notice that we were redirected
to the admin page,
and now we don't see this
"You are not authenticated" content,
but instead we see the real admin page content.
So we make it past this if-check here,
and the rendered admin template was returned.
So this proves that this user is now considered
to be authenticated.
And the other thing that changed this
if we now have a cookie here,
and that's our session cookie.
And this cookie,
if you have a look at the cookie value,
in the end stores a cryptic string here,
which includes the ID of the session.
And we can see that, on the other hand,
if we got back to the terminal
or command prompt.
And we connect to the Mongo DB database
with the Mongo shell.
In there, if I use my auth-demo database,
and I then access these sessions collection
and find all entries in there,
I find one entry in there at the moment
because I only logged in once here
and at the moment, that's all the session data
that is then created by my website.
And here you see how such a session looks like
in the database.
This entry was generated automatically
by the session package
with help of the Mongo DB session store.
There is a bunch of metadata stored here.
For example, some data about the cookie,
when it expires, if it does expire.
Here no special setting was chosen.
And here we also see an expiration date
for the session overall.
Though that's a bit deceiving.
This means that the session would expire on this date
if it wouldn't be used and updated at all until then.
If you do update the session in any way,
if any other data is written to it
or your session store automatically updates it
whenever the session is being used,
which most stores do,
then this session will prolong.
And then it's really that cookie expiration,
which by default is not set,
which does determine when the session should expire
no matter if it's being used or not.
By default, no expiration date is set on the cookie
and therefore the session actually won't expire.
It will keep on running.
But if you would want to set one,
you can go to your session configuration options
and there set the cookie option,
and then for the cookie, the maxAge option.
And this one's a maximum age for the cookie
and therefore then also for the session
after which this session will expire
and the user would, for example, need to log in again
if the session is being used for authentication,
as we are doing it here.
Now, maxAge wants a value in milliseconds
and you can set it to a fixed value.
Or what you'll do very often
is that you calculate it just in time
as this will simply be more readable.
A thousand milliseconds are a second,
so you could write 60 times 1000,
to calculate a duration of one minute.
And then you could multiply this by 60
to have an hour.
Multiply it with 24, to have a day.
And then maybe multiply it with 30.
And that is how you could set an expiration date
of 30 days after which your session
would definitely expire if you want that.
Or you don't set the value as it's by default,
so there is no value set initially.
And then as mentioned, this cookie and therefore
also the session won't expire at all,
it comes down to what you need
and want for your website.
Now, if no expiration is set,
then indeed the cookie in the session
doesn't expire by default,
but most browsers will still actually clear the cookie,
and therefore also the session since a session,
without a cookie won't work,
if the browser shuts down.
So if you entirely close a browser.
So that's just something to be aware of
that the session will close then effectively
if a user would entirely close a browser.
So that is what influences when the session
will die in the end,
and when it will be reset automatically.
And then we here also see the extra data we stored.
The user object and the isAuthenticated data.
Here we've got the user ID and email
and our isAuthenticated flag.
And then this session also has an ID.
And this ID, which we see here,
Q_v4, and so on in my case,
that's the ID you also see
somewhere here in your cookie.
Not from the very start, but somewhere in there,
you have this session ID.
And that's how this cookie
is mapped to the session.
And this cookie is automatically sent
to the server with every request
that's generated on your page.
The browser will do this automatically for you.
Also for Ajax requests, by the way.
Their cookies are also sent along.
So whenever you send a request to this domain now,
for which the cookie was registered.
So our local host domain, in this case,
all those cookies are sent along
with the request automatically by the browser.
And therefore, on the server,
they can be parsed,
and they will be parsed automatically
by the session package here in the end.
And the session package will look for its session cookie,
automatically extract the ID from that cookie,
the session ID, I mean,
and then look for a session with that ID
in the database so that it finds this session
for this user here.
And then it's able to see that this user
is authenticated.
And for example here,
if I open a new incognito tab,
so that's a new tab, a new incognito tap.
There I'm not authenticated
because this is like a new user to the server.
Sure it's on the same computer,
the same machine.
But as I mentioned before, this doesn't matter,
the IP doesn't matter.
But since it's a new incognito tab,
it didn't keep any of the cookies
set for the other tab
and therefore here If we have a look at the cookies,
I have no cookies.
So therefore this year is a new visitor to my server,
a new visitor without a session
and therefore of course also
without any authentication data.
And hence this visitor in this tab
is not granted access,
whereas this visitor here
can access the admin page just fine.
So that is how this all works.
Sessions are connected to different visitors
and incognito tabs act as new visitors
because they don't take any cookies
from other taps and therefore
this is now how we can implement
authentication with cookies and sessions.