-> Here is my frontend code
Visit my live website here: https://alek-password-manager.netlify.app
- E-mail: [email protected]
- Password: test
I created this project with one of the main goal being that to challenge my web security skills. In the process I learned that while you can't control which links the frontend user clicks or which apps they may install (that could be malicious), we as developers should focus to minimize those risks by maximizing security steps required to access sensitive data. All that must be achieved by finding a sweet spot between trying to not annoy our users and securing their data.
- With React I avoided any unnecessary re-renders & used strategic re-renders to my advantage for features like
multi-device
for example: user A logged on 'device A' modifies its "password vault", then the same user A but logged on 'device B' - when they try any CRUD operations on their (unrefreshed) "password vault" page - they will get the latest changes (made on device A) without any refresh on their device B. While also my goal was to use as minimum libraries as possible and to keep following the DRY principle by building reusable components myself & creating custom hooks.
- I implemented "refresh tokens" which are long-lived besides "access tokens" which are short-lived. However I gave the clients an option to stay signed-in until they manually log out in cases where they fully trust their device & network. The user requires a valid refresh token in order to request a new access token - on success they get both new accessToken & refreshToken - while on invalid or expired refresh token the said token is removed from the database and the user is alerted accordingly and redirected to the login page on the frontend.
- Anti-hacks security: in case where the user's refreshToken is not inside the database -> it means the refreshToken was used by someone else (I suspect it's a hacker) and I alert the user about the potential threat.
- "Multi-device" feature allows the user A logged on device A to "log out all devices"(meaning: empties out the array of refreshToken's in the database) which will technically log-out the same user A but logged on device B & my "safety alert-message" about anti-hacks will get triggered, therefore, the message itself has to have empathy about such a case scenario where some of their family members clicked the "logout all devices" button on another device as an example. It was kind of like a Catch-22 where I couldn't have a separate message and the solution was a guided-empathetic-message to make sure I'm not misleading my users.
- Clone this project.
- Navigate (cd) into your project directory.
- Run
npm install
in your command line. - Run
npm start
in your command line. - Visit http://localhost:3003 in your browser!
- Optional: you may want to connect it with my frontend project.
1. In order to run my full-stack app successfully on your local development by combining this server & my frontend you may want to remove all the domain
properties on authentication (refreshToken
's) cookies creation or just modify domain
's values to the appropriate URL your frontend runs on.
2. Your secretPasswordEncryption
secret inside .env
file must be of 32 bytes (which equals to 256 bits) which means it must be exactly 32 characters long.
3. You must add your frontend URL to the allowedOrigins
file located in config/allowedOrigins.js
directory so that CORS will allow the requests to be made to the server.
Clone with SSH URL: git clone [email protected]:Aleksandar15/Password-Manager-server.git
Clone the frontend code from here & follow the instructions there.
More info (extra reminders for me):
PersistLogin
on frontend could be named "PersistLoading
" because throughout development I modified it to persist "Loading
" page always and to never give an 'empty skeleton-page' of a protected route (see ex. #1.1). I compared my app to instagram for inspiration and achieved exactly what I imagined. All the while auth-checks are handled in each component and they all have "Loading
" as default state which is pretty cool.
1.1 Example: to never give away an 'empty skeleton-page' of a protected route (ex. /manager
) to unauthorized user - and the other way - to never visually show unauthenticated route like /login
to authorized user and instead after "Loading" -> redirect them back to authorized route /manager
.
-
refreshTokenController
on the server is rotating each valid non-expiredrefreshToken
with a new one and I am passing the remaining 'expiryTime' from the old one which was now "invalidated" - meaning it was removed from database & replaced withnewRefreshToken
. That's a perfect security feature I implemented on my app. -
Axios
frontend utils created usingaxios.create
method by default parses my JSON data behind the scenes hence why I don't useJSON.parse
on my backend. If I were to send a JSON I'd need thetransformRequest
function. -
Server is deployed on fly.io which allows only 1 server to be run for free which is available 24/7 (no sleep time), well actually 5 "clusters" are free but the node.js server takes up 2 and the postgres database 1, so the remaining 2 can't be used for another server.
- As of April 2023 they seem to have fixed that issue, now: 1 server takes up 1 VM (virtual machine) and 1 database takes up 1VM, but free allowance is reduced to 3VM, so it remains only 1 full backend for free.