Press "Enter" to skip to content

MERN Stack & GraphQL – #10 Authentication (Part 2)

so back in our off GS file we’ll try to
find the user by the email address and
if we can’t find it we’re gonna throw a
new authentication error so we could
either be very specific and say that
email is incorrect or we can be very
generic and just say incorrect email or
password please try again in fact we can
go ahead and extract this into a
constant let’s call it message and we’ll
pass in a message to the error
constructor like this and of course we
need to make this function asynchronous
with the async keyword and now once we
have the user we need to validate the
password for that user I’ll be useful to
add a helper method to the user model so
let’s go back to user J s and our models
we already have a pre safe hook which
hashes the password before the model is
saved we’re gonna add another method so
let’s reference the user schema in this
case it’s going to be an instance method
so we’re gonna reference methods
property so this one you’re gonna be
able to call on the actual user instance
in this case we could do something like
user dot matches password so this will
be the name of the actual method now the
difference between matches password and
doesn’t exist is that it doesn’t exist
method it needs to be called on the
model itself so you could do user
uppercase dot doesn’t exist because it’s
a static method but for an instance
method you can call it on the actual
instance of the model like the user that
we found by the email address so we’re
gonna do lower case user dot matches
password and let’s add that method so
it’s going to be a function that accepts
a password once again it’s going to be a
traditional function and not an arrow
function because we need to have access
to the this keyword so we’re gonna go
ahead and return bcrypt
dot compare but of course we can just
import that method just as hash so let’s
import compare and now the first
argument will be the password that we
receive as an argument so this is the
password that was supplied as an
argument to our query and the second
argument will be the actual hash so this
will be this dot password this in this
case will be the actual user model so
for example the user that we find by the
email address once again and password
once again is what we’ll receive as the
argument to the query so now we can save
file and now that we have a matches
password function we can go ahead and
call it passing the password argument
but we also have to make sure to put a
weight on it because it’s asynchronous
and now if this operation fails that
means that the passwords don’t match so
we can throw a new authentication error
once again we could be very specific and
just say password incorrect or
alternatively we could also be very
generic and once again pass the existing
message which is going to say incorrect
email or password please try again and
of course we also need to import the
user model from models in fact it’s
going to be in the same level because
auth is going to be at the root of this
source file
so from auth we’re gonna go to models
and XJS and then to user is to get the
actual model and finally we’re gonna
return the user instance so this will be
the actual user model that we were able
to find and now if the authentication
fails so if the user with the given
email address doesn’t exist we’re gonna
throw an error and also if the passwords
don’t match we will also throw an error
with the same exact message so now back
in here
assuming that we get a user object we’re
going to go ahead and reference the
request session user ID once again it
doesn’t have any special meaning this
will be a custom variable in the session
so we’re gonna set a user ID and this 1
will equal user ID so once this request
is done the session middleware will
actually set a cookie on the response
object so this way the user will be able
to access the resources on the server
with that session ID cookie so now for
these sign out mutation what we can do
is we can check that the user is signed
in because it doesn’t make sense to sign
out if you’re not signed into the system
and now what we can do is we can once
again either put all the logic in here
but because we already have the author
GS file with the helper method we could
add another function let’s call it sign
out so in this function we’re gonna do a
request dot session dot destroy this
will accept an error call back if there
was an error we could return back that
error but what I’m thinking instead is
we’re going to actually return a promise
so what I’m gonna do is I’m going to
wrap this function once again it’s gonna
take a request and a response the
request is necessary because we need to
access request
but the response is also needed because
we want to clear out the cookie before
the user sends out so once again I’m
going to return a promise in this case
what we can do is we can have a callback
function so it’s going to accept resolve
and reject and now inside of that
function we’re gonna paste in the call
to session destroy’ and if the error
occurs we’re gonna simply reject the
callback with that error if we didn’t
have any error we’re going to call Raz
clear cookie of course we need to have
access to a session name and this one of
course we can import as well so it’s
gonna come from the config file which is
in the same level and then once the
cookie is cleared out we could do
resolve with a boolean set to true so
once we have a sign out function let’s
also import it from here so we’re gonna
delegate to that helper function let’s
return auth dot sign out so we’re gonna
pass in the request as well as response
and if you remember the response is
gonna come from context as well once
again that’s because we define the
context as a function and here so we get
the request as well as response objects
so now let’s go back to our terminal I’m
gonna clear it out and I’m gonna try to
do a yarn duck
so let’s see if we made any mistakes it
was like we forgot the me query so let’s
go back and fix that so in type
definitions I’m going to add another
query I’m gonna call it me so this one
is not going to take any parameters but
it’s going to return a user if you’re
signed in back in in terminal we get the
link to our server so in the past we’re
able to execute queries without being
logged in so now let’s try to do a query
to users as you can see we get an error
which says you must be signed in that’s
because of the helper function that
we’ve set up for the user’s query so
it’s going to first check if you’re
signed in to the system before you can
access any of the resources on the
server and the same thing as of course
going to apply to the me query so this
one is a helper query to get the
information about the currently signed
end user so now if I try it of course
I’m gonna get an error because we’re not
send into the system yet so because I
know we don’t have any users in the
application let’s go ahead and try to do
a mutation we’re going to call the
signup mutation we’ll pass an email I’ll
quickly fill it out so we’ll get an ID
email use your name and name so this
will create a user we’re also expected
to create a session ID cookie now if I
look at the cookies using the edit this
cookie extension you’re gonna see that
the cookie is not found there and this
is because we forgot to add a statement
to set the user ID on the session once
we create the user so the exact same one
that we do in a sign-in mutation once we
validate the users credentials we’re
gonna want to copy that statement and
also put it over here so before we even
return the user we’re actually going to
put it into a constant so we’re gonna do
in a wait on user create and once we get
the user we’re gonna set that user ID on
this session and finally we’re going to
return back the user object itself and
you’re gonna see that we still don’t get
the cookie and that’s because the graph
QL playground does not allow cookies by
default so what we need to do to enable
cookies is we need to change the request
credentials setting from Amit to include
like this but the downside with this
approach is it’s actually only going to
work as long as you have these settings
saved in your current browser session so
if you clear out the history and local
storage from your browser of course all
of these settings will also get cleared
so it’s a lot easier to set them up on
the server and if you have all of the
dependencies up to date now specifically
I’m talking about the Apolo server
dependency so if your Apolo server is a
two point two point two which is
currently the latest one you can go back
to your index.js file now what we can do
here is we can provide a configuration
for the playground so we’re gonna do is
we’re gonna check if we are in
production so if you know an environment
is set to production we’re going to pass
back a value of false so this is going
to completely disable the playground
otherwise we’re gonna pass a
configuration object we’re gonna pass a
settings property and once again in this
case we’re gonna reference the request
dot credentials property so let’s put it
in and we’re gonna set it to include
like this so this will in fact include
the cookies as a response from the
server and on the same note let’s
actually go ahead and also disable any
course requests so set course to false
now what this is going to do is it’s
going to limit the requests to the
server only to the current domain so in
this case it’s only going to be
localhost 3000 like
you’re gonna try to send a query from
localhost 4000 for example on the front
end it’s actually going to fail because
of the missing course headers from the
server now once we start working on the
front-end part I’m gonna show you how
you can mitigate this issue but for the
time being we’re gonna put a maximum
security and we’re gonna set the course
headers to false so only if you are on
the same domain can you actually query
the server so we’re gonna save this file
so let me go back in here I’m gonna do
it one last time so let’s do max 1 5 and
once we run it let’s make sure we get
back the cookie and as you can see in
this case we actually get a session ID
cookie and this one of course will
contain the idea of this session and you
can see that this cookie is going to
also expire in two hours now to prove
that this session was actually created
I’m gonna go back to the terminal let me
open a new tab and because I already
have the radical and installed using
Redis tools what I’m gonna do is I’m
gonna execute the Redis CLI command so
let’s actually do – – help in this case
we can pass a few arguments so for
example we can supply a host as well as
port and also a password so let’s do
exactly that so I’m gonna do Redis CLI
with a host pointing back to Redis Labs
also pass a port and my password so once
I’m in if I do scan 0 you’re gonna see
that we get one object it’s key is
session callin the session ID so if we
copy the name and if we do get on that
key you’re gonna see that we get a JSON
object in this case we get the cookie
with the cookie information in this case
we’re gonna get the maximum age of two
hours we get the expiry date in this
case the time is 9:40 because it’s in
GMT but we also see that it’s not secure
it’s HTTP only we get the path the same
side attribute and we also get the
actual user ID so if you compare that
user ID to the actual ID of the user
you’re gonna see that the to match so if
we go back over here that’s the exact
same user ID that we get from the
application and on the same note you’re
gonna see that this ID after SAS column
this one of course matches the actual
session ID so if we once again look at
the value stored in the cookie you’re
gonna see that it’s a string once again
we can ignore the first part which is s
Colin URL encoded by the next part
before a period so before the actual
this one will be the same exact such an
idea so once again this session ID is
gonna equal the same exact value that is
stored in the Redis as a key to that
session you can see that the two values
match so this is how these sessions are
stored so now having a session ID cookie
we can actually write a query with me we
could get the ID the email for example
and this will still work and it’s
actually going to continue to work even
after we restart the server so for
example in the past because we were
using an in-memory store the moment you
would restart the server all of these
sessions would be cleared out but
because we store the sessions in Redis
right now if I restart the server I
should still be able to access my
session information as long as the
cookie is still valid so before they
cookie expires I should still be able to
fire off queries to the server and get
the information I need of course we
already tested the signup mutation it
seems to work just fine but imagine that
I cleared out the cookie clear out this
cookie and I’m gonna try to write
another mutation so in fact – let’s try
to write out a mutation to sign in will
pass an email as well as the password
and we’ll try to get back an ID and be
also the name so if you run it you can
see that we get back the user object and
there should also create a session ID
cookie and as you can see it does but if
we clear it out and I try let’s say
wrong email this will fail because we
can’t find the user with that email and
if I pass a wrong password this will
also fail because the passport won’t
match and in this case of course we
won’t get the session ID cookie once
again I’ll try to login we get back to
user object and we also get logged in
and if I create a new mutation let’s try
to sign out and if we run it like this
you see that we get true and you will
also find out that the cookie also gets
deleted now if we try to sign out once
again of course this will fail because
we have to be logged into the system but
only contrast the assigning mutation is
actually idempotent that’s because we
can fire up the same mutation multiple
times it only creates a cookie once and
we’re gonna see it in this window using
the edit this cookie extension but once
again we can run the same mutation
multiple times it’s just going to return
back the same exact user object but for
other methods like to sign out we want
to first make sure that we signed in and
of course for the sign up mutation we
also want to make sure that we’re signed
out because if we are signed in it
doesn’t make sense to create the user so
if you look at the schema for the user
right now
it’s already pretty solid we have the
sign up mutation we can also sign into
the app and of course we can sign out
from the app as far as getting the user
by the ID this might be useful later on
in the front-end so I’m going to keep
that query as well so in the next video
we’re actually going to move on to
messages and chats so we’re actually
going to start working on the
communication portion in the app but for
the time being this should suffice so
this has been authentication and graph
QL I hope you enjoyed the video and I’m gonna see you next time take care

Please follow and like us: