Somehow I find myself in the world of authentication again! I thought I’d struggled through it enough in the past that surely I’d be able to add auth to a new app I’m working on without much trouble. WRONG. 😂
I’m making a private website that needs to be password protected. It used to be a Wordpress site, and apparently this is a little more straightforward on apache servers with an
.htaccess file? (That might be wrong, but it’s what I understand now, and a rabbit hold I decided not to go down!) But this new site is on a Node server so I would need to find another way to implement auth.
Just copy what I did before—this was my first instinct. I’ve been through auth on a number of projects and got it to work several ways, so this should work, right? Well…
Passport could work with the
passport-local strategy. But must I associate a username with the password (yes)? And so I really need to create a new database User model to store it (yes)? And wait, now I need a session store (not technically but it’s best practice and we can’t avoid those!)? And OMG look at the Passport documentation, it explains nothing. Even the helpful articles are tomes! 😩
Still I tried this anyway, and found that the best documented way to implement
passport-local seems to be combining a MongoDB data store and
passport-local-mongoose. Well my app already has a Postgres data store. So then I look at previous projects where I implemented
passport-local-sequelize, check the docs, and see that it hasn’t been kept up to date with the latest releases of
And isn’t all of this overkill anyway? I think so, so I look for a simpler approach!
I could go the roll your own route, and looked at a few ways to do this. This article and repo used a similar method to what I used in the value app where you store a hashed password and send cookies to the client. I also looked at a new-to-me package
express-basic-auth which seemed to do the trick with the benefit of being bare-bones, only it’s not extendable to authenticating the user on specific routes, which for me is the whole purpose of this…another dead end.
Honestly going through all of these options was a lot! So then I thought I could go back to the old faithful Auth0…that is, until I re-read some of my old posts detailing all of the nitpicky issues I had on previous projects. Knowing I will deploy this app on Heroku (and we know how that turned out), I decided it wasn’t worth the trouble or cost again.
All of the above led me to try a new method I’ve not used before: JSON Web Tokens! This article and repo gave a relatively simple walk-through of how to implement JWTs using the
jsonwebtoken package to encrypt the tokens, and
argon2 to hash the passwords.
I adapted the code from this walk-through successfully and was able to register a user and give them a JWT. That user was also able to log in with a valid JWT.
Then I got to the part of protecting routes…roadblock. This method will work for the API where I can attach headers to each request, but to protect routes on a normal
POST app-level route, I’d still need to implement some kind of session store. There were also some gotchas around invalidating a token, for example if you want the user to be able to log out (as opposed to just letting their token expire).
I’m tired of working on this and want to actually work on the app now. I can see why people default to a tool like Auth0 or Okta!
So I decided to use a separate database for the user & session store following this step-by-step which uses Passport, MongoDB and
passport-local-mongoose, and it worked great in the end.
The only issue was getting Express to serve the file directory of the Vue app’s static files…
I could serve the login page (and Express EJS template) and the Vue app by setting up two static file locations:
// Serve client static files
The problem was that the Vue app would render whether or not the user was logged in, even if the
client/dist/index.html file was only served from a protected route.
I learned how to layer in the authentication by stacking my
loggedIn middleware instead:
Same exact line of code, but called this way it only rendered the
…when it’s actually now located here:
So adding some Vue config to the client’s
package.json file did the trick:
Note: depending on how your Vue app was originally set up, you might need to add this setting to the
vue.config.jsfile instead. See docs for all settings.
I now have auth running successfully, and the static pages can only be accessed if the user is logged in. 🎉🎉🎉