AdonisJS 6 Session Authentication in 15 Minutes
In this lesson, we'll learn how to add authentication to a new AdonisJS 6 application using the session guard. In these 15 minutes, you'll learn how to register a user, logout a user, verify a user's credentials and log them in, and more.
- Author
- Tom Gobich
- Published
- Apr 18
- Duration
- 15m 18s
Developer, dog lover, and burrito eater. Currently teaching AdonisJS, a fully featured NodeJS framework, and running Adocasts where I post new lessons weekly. Professionally, I work with JavaScript, .Net C#, and SQL Server.
Adocasts
Burlington, KY
Transcript
AdonisJS 6 Session Authentication in 15 Minutes
-
(upbeat music)
-
So first let's go ahead and get ourselves
-
a new AdonisJS 6 application
-
by doing npm init adonisjs@latest,
-
and we'll call this adonisjs6 session auth.
-
Let's run that, and then it will ask us
-
what starter kit we'd like to start with.
-
Today we're gonna be talking about this as a monolith,
-
so everything within one application.
-
In a future lesson, we'll take a look at this
-
within split applications as well.
-
So for this lesson, we'll select the web starter kit.
-
Then we're gonna use session authentication,
-
and my database driver is Postgres,
-
but do select whichever one's applicable to you here.
-
We'll have it install our dependencies.
-
Then while it's doing that,
-
let's open up our text editor,
-
go into open, find our project,
-
finds within code, then down in tutorials,
-
AdonisJS 6, session auth.
-
Let's open that up, and our output's gonna show
-
that we're missing an environment variable for db database.
-
We'll take care of that here in a second,
-
but before we do, let's dive back into our terminal
-
and make sure everything installed okay, which it did.
-
So before we start our server up,
-
let's go ahead and take care of our environment variables.
-
For the most part, everything that's here already
-
is a okay to leave as is.
-
We just need to fill out our database password.
-
Mine's the very secure password,
-
and then our database name.
-
I believe I have one called test.
-
Then let's hold command P and dive into our routes file.
-
Let's create our routes for our authentication.
-
So we'll do router.
-
And we'll put these inside of a group.
-
So we'll define a callback function,
-
and any routes that we define within this group
-
will get applied to the group.
-
So we can name this group as auth.
-
If you wanted to prefix the URL as well,
-
we could do that there too.
-
We'll leave that out for right now.
-
As for our routes itself, we'll do router.get/register.
-
And we're gonna need some controllers
-
to actually house the logic with it.
-
So let's jump back into our terminal, clear that out.
-
Let's go ahead and CD into our project.
-
So I named mine AdonisJS6, session auth.
-
There we go, clear that out once more.
-
And then we'll do node is make controller.
-
And what I like doing for my authentication controllers
-
is having one controller per action
-
that we have for authentication.
-
So we'll have one controller for registration,
-
one for login, and one for logout.
-
And that just helps keep things clean
-
as our authentication logic grows
-
throughout the life of our application.
-
And furthermore, we can put all of them
-
inside of a single directory called auth.
-
So if we just do auth/,
-
and we'll put whatever we name here.
-
So let's do register to create a register controller
-
inside of an auth directory.
-
Then for our register controller,
-
let's also create a show and a store method inside of there.
-
And let's keep our register name singular by doing -s.
-
Let's run that, and there we go.
-
While we're here, let's hit up and change register to login.
-
And let's run that, and we'll do one more for logout.
-
So let's go down to log and add out, there we go.
-
So our controller should be good, clear that out.
-
And let's go ahead and verify that our server will boot up.
-
So let's do npm run dev awesome.
-
Let's hide that away,
-
and let's dive back into our text editor.
-
So for our register route,
-
we're gonna want to use our register controller.
-
So we hit tab to auto import that.
-
And specifically for this one,
-
we're gonna wanna use the show method.
-
And then we'll name this route as register.show.
-
So the full route's name is now auth.register.show.
-
Since we've defined this route
-
inside of our auth router group.
-
Give that a save to fix all of the formatting.
-
Let's give this a quick copy.
-
Switch our get to a post.
-
This will handle our register form submission.
-
We can keep the URL the same here.
-
Switch over to our show and change that to store
-
and change our show to store there as well.
-
Okay, give that a save.
-
And let's dive into our app folder,
-
controllers, auth,
-
and let's dive into our register controller.
-
We're gonna start with our show method.
-
What we're gonna want is to extract view
-
out of our HTTP context and return view,
-
render pages slash,
-
and we'll create a view at auth slash register.
-
Give that a save, and let's go create that.
-
So resources, views, pages,
-
let's right click on pages, new file,
-
create a folder called auth.
-
And inside of that folder,
-
we'll create a file called register.edge.
-
So that we don't need to redefine all of the HTML5 markup,
-
let's right click on our views directory, new file,
-
let's create a folder called components,
-
create a folder inside of components called layout,
-
and a file inside of layout called index.edge.
-
Once we have that, let's dive into our views,
-
pages, homepage, give everything there a copy,
-
and let's paste that into our new layout file.
-
Replace the body contents with three curly braces,
-
a weight, and let's render out our main slot.
-
So we'll do slots.main there.
-
We'll also allow ourselves to define a title.
-
So we'll do two curly braces to add an interpolation there.
-
And we'll just render out a title
-
or an empty string hyphen Adonis JS6 session auth
-
to serve as our default title there.
-
Give that a save, back into our auth and our register page.
-
And we can do @layout title register,
-
end our layout, and let's add an H1 register.
-
We'll add a form with a label, a span.
-
We're gonna want a full name.
-
So we'll have an input type equals text,
-
name equals full name, value equals,
-
and we can grab the old value that was submitted
-
or the full name.
-
And if one was not previously submitted,
-
we'll default that to an empty string and end our input.
-
Then we'll display any errors with input error,
-
reach for our full name errors, and then end that.
-
And if we got any,
-
they'll be injected as dollar sign messages.
-
We just join those messages as a comma delimited list.
-
Let's give that a copy
-
'cause we're gonna need it two more times
-
and paste it in those two times.
-
Our second one is going to be our email.
-
So email there, type will be email,
-
name will be email, old will be email,
-
and our full name will be email.
-
Then we'll dive down to this one,
-
and this one will serve as our password field.
-
So we just need to switch all of these
-
to password as well.
-
Now you can extract this out into a component
-
so that you only need to define this once.
-
And our Let's Learn AdonisJS 6 series
-
covers exactly how to do that.
-
Okay, then we'll have our button type equals submit,
-
and we'll add in register for the text for that button.
-
So at present, this form would not work.
-
We haven't rigged it up to anything quite yet.
-
Let's go ahead and open up our browser,
-
head into slash register to view our registration page.
-
Not pretty, but everything looks correct.
-
Awesome.
-
Let's rig up our form real quick.
-
So this will be a method of post,
-
and an action will point to our route,
-
auto off, register, store.
-
We're also going to want this to submit with a CSRF token.
-
So we'll call the CSRF field to inject a hidden input
-
with a CSRF token into this form.
-
If we dive into our config shield
-
and scroll down to the CSRF section,
-
this is enabled by default.
-
So if we don't include that, our form will fail
-
due to that shield configuration
-
and CSRF protection being enabled.
-
Let's dive back into our terminal,
-
stop our server for a brief second, clear that out.
-
Let's create ourselves an auth validator file.
-
So do node is make validator,
-
and we'll just call this auth.
-
And then while we're here
-
and while we have our server stopped,
-
let's go ahead and also migrate our database.
-
So we'll clear that out.
-
We'll do node is migration,
-
and then you most likely will just need to call run
-
if you're working with a brand new database.
-
I, however, am reusing a database from a previous lesson.
-
So I need to call fresh,
-
which will truncate and drop all tables
-
inside of the database, regardless of what they are,
-
and re-migrate with our fresh migrations.
-
So I'm gonna run that, and there we go.
-
So it dropped all of my tables
-
and re-migrated the one migration that we have
-
to create our users table.
-
Let's clear that out, and we can boot back up our server.
-
So npm run dev, and jump back into our text editor.
-
Now we need to take care
-
of our auth register store handler.
-
So we'll jump back into our register controller.
-
We're going to need our request
-
and our response from our HTTP context.
-
Let's grab our validated data.
-
So we'll do const data equals await request,
-
validate using to use our validator,
-
and let's go create that validator.
-
So we'll jump into our auth validators,
-
export const register validator equals vine compile,
-
vine object, and provide in our full name of vine string,
-
and we'll set a max length to 100 characters.
-
For that, we'll have our email of type vine string.
-
Define that it should be an email,
-
and let's also normalize that email as well.
-
And then lastly, we'll have our password
-
of type vine string, and let's require that
-
to be at least eight characters long.
-
So we'll set a min length of eight there.
-
Okay, we'll give that a save,
-
jump back to our register controller,
-
and now we can pass that validator
-
directly into our validate using.
-
So we'll type out register validator
-
and hit tab to auto import that,
-
and provide that directly into our validate using
-
with our request.
-
This will then pluck the data off of our requests
-
and validate it against our register validator,
-
and provide us back that validated data
-
of our full name, email, and password.
-
So we can then directly use this data to create our user.
-
So we'll do const user equals await user,
-
hit tab to auto import that model,
-
dot create, and provide in that validated data.
-
Once we've done that, we just need to log the user in.
-
And we're gonna wanna use the auth module
-
provided directly from our HTTP context to do so.
-
So we'll extract that out as well.
-
We'll then await auth to use our web session guard
-
to log in the specific user that we have created.
-
Once we've logged in that user,
-
we can then return response dot redirect.
-
And we haven't given our homepage a name quite yet,
-
so we'll just do to path and provide slash
-
to go back to the homepage.
-
So there is our registration flow.
-
Let's go ahead and dive now into our homepage
-
and give us something to say
-
whether or not a user is authenticated.
-
So we can do at if auth user to determine
-
whether or not a user has been authenticated
-
for the current session.
-
And let's end that if.
-
So if we have an auth user,
-
then we'll say logged in as,
-
use string interpolation to reach for auth user,
-
and we'll display out the full name.
-
Let's give that a save.
-
And if we're not logged in,
-
so we'll add in an else here.
-
Let's display a quick link to our register page.
-
So ahref route auth register shell
-
and provide it in the text register there.
-
Let's give that a save, jump back into our browser.
-
And let's go back to our homepage real quick
-
just to verify that it only shows register here.
-
Give that a click.
-
We go into our register page.
-
I'll enter in my full name,
-
some email and some password.
-
We'll hit enter to submit that.
-
And everything appears to have worked.
-
We got redirected back to our homepage,
-
but we still just see register.
-
So we are actually authenticated,
-
but this request just doesn't know it
-
because we haven't informed it to check
-
for that authenticated user yet.
-
So let's go and do that real quick.
-
So let's hold command P and dive back into our routes.
-
And let's switch our home route
-
from using the on to router.get/
-
so that we have to find this with an actual route handler.
-
And we'll just return ctx_view_render_pages.
-
Hold, okay, let's get rid of that.
-
Then to check for authenticated user on a session,
-
we just need to await ctx_auth and call the check method.
-
This will check for an authenticated user
-
and populate our auth.user
-
with that authenticated user's details if anyone is found.
-
Otherwise it will continue onward
-
and our auth.user will just be null.
-
So we can save that.
-
And with that save,
-
let's go ahead and dive back into our browser,
-
give the page a quick refresh.
-
And there we go.
-
We see we're logged in as Tom Gubbage now.
-
Awesome.
-
So before we can cover logging in,
-
we need to be able to log back out.
-
So let's do that real quick.
-
Dive back into our text editor,
-
jump down to our routes,
-
and let's add in a new one called router.host/logout.
-
We'll have our logout controller handle this.
-
And we created this with a show in store.
-
Let's just call that one handle.
-
We'll go fix that here in a second, is logout.
-
We'll give that a save.
-
And let's go dive into that logout controller
-
and replace one of these methods with just the word handle.
-
Get rid of the other one as well.
-
Within here, we're gonna want our response
-
so that we can redirect back away.
-
And we're gonna want our auth as well.
-
So we'll just await auth.filt_to_use,
-
the web guard, and log out the current session.
-
Once we've done that, we're good to just return,
-
response, redirect, do,
-
and we'll point it to our homepage.
-
Give that a save.
-
And let's dive back into our homepage.
-
And if we are logged in, let's add in a quick form,
-
method equals post, action equals route, auth.logout.
-
Add in that CSRF field and the button of type submit
-
that says logout.
-
Give that a save.
-
And now we should be able to dive back into our browser.
-
We see that button, we can click it,
-
and voila, we're now logged out.
-
So lastly, we just need to add in our login flow.
-
So let's start with our routes once more.
-
So we'll dive back into our routes file.
-
Let's give both of our register routes here
-
a copy and a paste.
-
Click in the middle of our register word,
-
option command down to get double cursors,
-
option right arrow to jump to the end of the word,
-
and option shift left arrow to highlight
-
and select the whole word for both lines.
-
Switch that to login,
-
option right arrow two more times,
-
option shift left arrow to select the entire
-
ready to give register controller.
-
And let's switch that to login controller
-
and hit tab to import that.
-
Option right arrow a few more times
-
to jump over to register,
-
and option shift right arrow
-
to select the entire word register.
-
And let's replace that with login.
-
Okay, give that a save,
-
scroll up and dive into our login controller,
-
show, we're just going to want view,
-
and we'll return view, render pages,
-
auth, login, and let's create that page real quick.
-
So we'll dive down to auth,
-
right click register, give that a copy,
-
right click auth, give it a paste.
-
With register copy selected,
-
we'll switch that to login.edge.
-
Do a quick find and replace for the word register
-
to login, we'll tell it to be case sensitive
-
with that search, and replace all finds.
-
Okay, then we'll scroll up.
-
We won't need our full name for logging in,
-
so we'll get rid of that.
-
We'll replace our auth.register.store
-
with auth.login.store,
-
and we should be good to go with our form now.
-
Give that a save, jump back up to our login controller,
-
and let's take care of our store method.
-
So we're going to want our request, response,
-
and auth out of our HTTP context.
-
And first we're going to want to grab that validated data.
-
So let's go back into our auth validator
-
and define one for logging in.
-
So we'll export const login validator
-
equals vine.compile, vine.object,
-
and I'm just going to go up and copy our email
-
and password, paste it in here,
-
and we'll get rid of the min length requirement
-
for our password,
-
since we aren't actually going to be storing it,
-
but just using it to check.
-
So we'll make that one a little bit more fluid there.
-
We do still want our email to be normalized though,
-
so that that check is the same as what they registered with.
-
So with that in place,
-
let's jump back into our login controller,
-
and let's get our validated data.
-
So we'll do const data equals await request,
-
validate using, and we'll use our login validator.
-
The next thing that we're going to want to do
-
is get the user matching the email
-
and the password that was provided in.
-
And if we take a look at our model for our user,
-
we're going to see this auth finder added in here by default
-
with the UID set to email
-
and the password column name set to password.
-
This auth finder is then composed into our user model,
-
and it's going to add in a couple of things for us,
-
like being able to verify our user's credentials
-
against what they've provided within their login form,
-
as well as hashing the user's password
-
whenever we actually store them into the database.
-
So during our registration step,
-
we didn't take care of that.
-
It just automatically happened for us
-
thanks to this auth finder.
-
Let's dive back into our login controller,
-
and let's use our auth model to determine
-
whether or not the user has provided a valid email
-
and password via our validated data
-
from our login validator
-
to get back the matched user for those credentials.
-
So we can do const user equals await,
-
import our user model,
-
and call verify credentials,
-
passing in the UID and the password.
-
So we can extract that out of our data
-
as email and password there.
-
And our email is our UID,
-
and our password is the password.
-
If these credentials are correct,
-
we will get back a user.
-
If they're incorrect,
-
this will then throw an error,
-
preventing further execution of our code.
-
Okay, then just like with our registration,
-
once we have access to that user,
-
we just want to await auth.use our web guard
-
to log in that user.
-
Once they're logged in,
-
we can return, response, redirect them
-
to our homepage path.
-
Give that a save.
-
Okay, lastly, let's dive back into our homepage
-
and give ourselves a link to our login page.
-
So we just copy our register link,
-
paste it in, switch that to login,
-
and switch this to login as well.
-
Give that a save,
-
and now we can jump back into our browser
-
and give everything a test.
-
So let's go to login.
-
We created a user with an email, [email protected],
-
and let's enter in that password, run that,
-
and now we're logged in as Tom Gobich.
-
We can log out.
-
Let's go back to login.
-
If we enter in [email protected],
-
which does not exist inside of our database,
-
and some password, we run that.
-
We get redirected right back here.
-
Our email is auto-populated,
-
thanks to that old check.
-
And if we wanted to,
-
we could display an error here as well.
-
So if we dive back into here,
-
let's go into our login page,
-
and let's add in a quick inspect call
-
to flashmessages.all to see what we're getting back.
-
Okay, [email protected], some password, run that.
-
There's our old email value,
-
and we can see that errors bag now has
-
E invalid credentials,
-
specifying invalid user credentials.
-
Okay, so we can dive back into our form here,
-
and up above our input fields,
-
we'll do @error,
-
and we just need to provide the key of the error
-
from the errors bag here,
-
which is E invalid credentials.
-
So we can give that a copy,
-
jump back into here,
-
and provide that into this errors tag.
-
We can end that,
-
and now if this error tag finds an error
-
called E invalid credentials,
-
it will provide that particular error via message.
-
So we could display that just like so.
-
Let's give that a save,
-
jump back into our browser,
-
give this one more test.
-
So [email protected], some invalid email there,
-
run that, and there we go.
-
So now we got invalid user credentials.
-
We keep the old email,
-
and the password is omitted from the old automatically
-
as a measure of safety.
-
1.0AdonisJS Authentication in 15 Minutes16m 7s
-
2.0How To Do Multi Model Authentication with AdonisJS and Lucid ORM18m 29s
-
3.0AdonisJS User Role Authentication in 15 Minutes15m 43s
-
4.0AdonisJS 5 API & Nuxt 3 SSR Authentication in 15 Minutes13m 58s
-
5.0AdonisJS 6 Session Authentication in 15 Minutes15m 18s
Join The Discussion! (0 Comments)
Please sign in or sign up for free to join in on the dicussion.
Be the first to Comment!