Skip to content

Delvoid/boilerplate-auth-express

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

35 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

Delv boilerplate jsonwebtoken auth API

Goal is to create a boilerplate project for users authentication. With the following functionality

  • Reguster a user

  • Verify email

  • Login

  • Forgot/Reset password

  • Logout

  • Get all users

  • Get single user

  • Show current user

  • Change password

  • Update user

  • Get user tokens

Installation

  1. Create mongoDB and setup MongoDB

  2. Clone the repo

    git clone https://github.com/Delvoid/boilerplate-auth-express.git
  3. Install NPM packages

    npm install
  4. Enter your MongoDB API's in .env

       MONGO_URI = ENTER YOUR MONOGO API
       JWT_SECRET= YOUR SECRET
       JWT_LIFETIME= LIFETIME

    Run the tests

    npm test

    Start the dev server

    npm run dev

(back to top)

Roadmap


Setup Basic Express Server
  • import express and assign to variable
  • setup start port variable (5000) and start function
Connect To DB
  • get connection string
  • setup .env with MONGO_URI variable and assign the value
  • import 'dotenv' and setup package
  • import connectDB() and invoke in the starter
Basic Routes and Middleware
  • setup /test GET Route
  • setup express.json() middleware
  • setup errorHandler middleware
  • setup 404 route not found middleware
  • import 'exress-async-errors' package

Morgan Pacakge

User Model
  • create models folder and User.js file
  • create schema with name,email, password, verificationToken (all type:String), isVerified - {type: Boolean, default: false}, verified type: Date
  • export mongoose model

Validator Package

Auth Routes Structure
  • create controllers folder
  • add authController file
  • export (register,login,logout) functions
  • res.send('some string value')
  • create routes folder
  • setup authRoutes file
  • import all controllers
  • setup three routes
  • post('/register') post('/login') get('/logout')
  • import authRoutes as authRouter in the app.js
  • setup app.use('/api/v1/auth', authRouter)
Register Controller
  • create user
  • setup fake verificationToken - 'fake token' - for verification functionality later
  • check if email already in use (schema and controller)
  • send response with entire user (only while testing)
  • send back success message and token
Handle Password
  • UserSchema.pre('save') - hook
  • this points to User
  • bcrypt.genSalt - number of rounds
  • bcrypt.hash
JWT
  • require 'jsonwebtoken' package
  • create jwt - jwt.sign(payload,secret,options)
  • verify jwt - jwt.verify(token,secret)
  • add variables in .env JWT_SECRET=jwtSecret and JWT_LIFETIME=1d
  • refactor code, create jwt functions in utils
  • refactor cookie code
  • setup func attachCookiesToResponse
  • accept payload(res, tokenUser)
  • create token, setup cookie
Login Route
  • check if email and password exist, if one missing return 400
  • find user, if no user return 401
  • check password, if does not match return 401
  • check if user.isVerified, if not 401
  • if everything is correct, attach cookie and send back the same response as in register
Logout Route
  • set token cookie equal to some string value
  • set expires:new Date(Date.now())
Verify Email Controller
  • create verifyEmail in authController
  • get verificationToken and email from req.body
  • setup a '/verify-email' route in authRoutes
  • check for user using email
  • if no user 401
  • if token does not match user token 401
  • if correct set
  • user.isVerified = true
  • user.verified = Date.now()
  • user.verificationToken = ''
  • save use with instance method
  • return msg:'email verified'
Email Setup
  • ethereal credentials (create account/login)
  • install nodemailer
  • create (nodemailerConfig, sendEmail, sendResetPasswordEmail, sendVerificationEmail) files in utils
Send Verification Link
  • setup sendEmail
  • setup sendVerificationEmail.js
  • pass arguments
Refresh Token Model
  • create Token.js in models
  • refreshToken,ip,userAgent - all String and required
  • isValid - Boolean, default:true
  • ref user
  • timestamps true
  • attempts Number: default: 0
Setup Refresh Token in Login Controller
  • create empty refreshToken
  • check for existing token
  • if existing token
    • check token is valid, if not 401
    • refreshToken = existingToken
    • attachCookiesToResponse
    • return status ok with tokenUser
  • create new refreshToken
  • get user-agent
  • create userToken
    • ip
    • refreshToken
    • userAgent
    • user id
  • attachCookiesToResponse
  • return response ok with userToken
Send Multiple Cookies
  • attachCookiesToResponse utils- jwt
  • accessTokenJWT
  • refreshTokenJWT
Create Auth Middleware - Access , Refresh Token
  • create auth middleware
    • create authenticateUser and authorizePermissions
  • [x]add dashboard route to test auth middleware
Refactor Logout
  • remove cookies when logging out
Forgot/Reset Password Functionality
  • Update User Model
    • passwordToken {type:String}
    • passwordTokenExpirationDate {type:Date}
  • Update authController
    • forgotPassword and resetPassword
  • Update authRoutes
    • post '/forgot-password' '/reset-password'
Forgot Password Controller
  • check valid email
  • find user
  • if valid user
    • generate a passwordToken
    • send password reset email
    • set passwordTokenExpirationDate
    • has password token
    • save to user
  • send ok status with msg
Reset Password Controller
  • check for token, email and password, if not 404
  • find user by email
  • if user
    • check if token has expired
    • get current date
    • If check password token matches &&
    • If check token has not expired
      • update users password
      • set password token to null
      • set passwordTokenExpirationDate to null
      • save user
  • return response password reset
User Routes Structure
  • add userController file
  • export (getAllUsers,getUserById,showCurrentUser,updateUser,updateUserPassword) functions
  • res.send('some string value')
  • setup userRoutes file
  • import all controllers
  • import userRoutes as userRouter in the app.js
  • setup app.use('/api/v1/users', userRouter)
GetAllUsers and GetSingleUser
  • Get all users and remove password
  • Get Single User where id matches id param and remove password
    • throw error if invalid id
    • If no user 404
ShowCurrentUser
  • get user from req
  • send response with user
UpdateUserPassword
  • almost identical to login user
  • add authenticateUser middleware in the route
  • check for oldPassword and newPassword in the body
  • if one missing 400
  • look for user with req.user.userId
  • check if oldPassword matches with user.comparePassword
  • if no match 401
  • if everything good set user.password equal to newPassword
  • await user.save()
CreateTokenUser in Utils
  • create a file in utils (createTokenUser)
  • setup a function that accepts user object and returns userToken object
  • export as default
  • setup all the correct imports/exports
updateUser with user.save()
  • add authenticateUser middleware in the route
  • check for name and email in the body
  • if one is missing, send 400 (optional)
  • use user.save() to trigger the UserSchema.pre('save') - hook
  • create token user, attachCookiesToResponse and send back the tokenUser
get logged in user tokens
  • create GetUserTokens
  • if no id passed get logged in users tokens
  • if id is passed find the tokens for that users id

revoke all tokens -- TODO

revoke a single device token -- TODO

Setup and Apply checkPermissions()
  • first user created is a admin
  • create checkPermissions in ultis
  • create authorizePermissions middleware
  • only admin can get all users list
  • users can cannot get other users by ID unless they are admin

(back to top)

TESTS

Setup
  • install supertest
  • install smtp-server
  • create tests folder
  • refacter app.js for supertest
  • create package script test
Register User
  • beforeAll connect to DB
  • afterAll disconnect from DB
  • afterEach delete users
  • returns 200 on valid requests
  • returns Success! Please check your email to verify account on valid requests
  • returns badRequest is email already in use with message
  • returns 400 if name email missing
  • returns 400 if name name missing
  • returns 400 if name password missing
  • returns validationErrors field in response body when validation error occurs
  • returns error for when name, password and email are null
  • creates user unverified
  • creates an activation token for user
  • password is hashed
  • [x]Password must have at least 1 uppercase, 1 lowercase letter and 1 number
  • email sent with verificationToken
  • returns 502 when sending email fails
  • does not save user to dabase if activation email fails
  • first user is created has a role of admin
  • second user is created has a role of user
Verify Email
  • verifies the email when correct token is sent
  • removes the token from user table after successful verification
  • sets the verified date after successful verification
  • returns msg with Email verified on successful verification and 200 status
  • does not verify email with incorrect token and returns 401
  • returns unauthorised request when token is wrong
  • returns unauthorised request when email is wrong
Error Model
  • returns path, timestamp, message and validationErrors in response when validation failure
  • returns path, timestamp and message in response when request fails other than validation error
  • returns path in error body
  • returns timestamp in milliseconds within 5 seconds value in error body
Login
  • returns 200 when credentials are correct
  • returns tokenUser: name, userId, role when login success
  • attach cookie if login is successful
  • returns 401 if user not exist
  • returns correct error body when auth fails
  • returns 401 when password does not match
  • returns 401 when e-mail is not valid
  • returns 401 when password is not valid
  • returns 400 when e-mail is missing
  • returns 400 when password is missing
  • returns 401 when logging in with an unverified account
Logout
  • returns 401 ok when unathorized request send for logout
  • removes tokens from database
  • removes stored cookies
Forgot password
  • return 200 with msg
  • creates password reset token on valid email and user
  • creates passwordTokenExpirationDate on valid user
  • return 400 if invalid email
  • sends email if valid user is found
  • returns 502 when bad gateway when sending email fails
Reset password
  • returns 403 when password update request does not have the valid password reset token
  • returns 400 when trying to update with invalid password and the reset token is valid
  • returns 200 when valid password is sent with valid reset token
  • updates the password in database when the request is valid
  • clears the reset token in database when the request is valid
  • verifys email if unverified after valid password reset
Get users
  • returns 403 if not authorised
  • returns 200 when valid auth and role admin
  • returns users list when valid auth and role admin
Get single user
  • returns 404 when user is not found
  • returns correct error body when user not found
  • returns 200 on valid user when admin
  • returns 401 when basic user tries to get another user
Get current user
  • returns 401 if not authorised
  • returns 200 and logged in user object without password if authorised
Update password
  • returns 200 with msg on valid request
  • returns 400 if oldPassword is missing
  • returns 400 if newPassword is missing
  • returns 401 if passwords do not match
  • returns 400 if password is not pass validation
  • updates the password in database when the request is valid
Update User
  • returns 401 when request without basic auth
  • returns 200 with msg on valid request
  • returns 400 if name is missing
  • returns 400 if email is missing
Get user tokens
  • returns 200 if valid auth
  • returns logged in users tokens if no id is passed
  • returns logged in users tokens if id is passed
  • returns 400 if invalid id
  • returns 403 if a user tries to get another users tokens
  • returns 200 if a admin tries to get other users tokens

Token expiration - TODO

  • [] returns 403 when refresh token is 30days old
  • [] refreshes token if expiered and refresh token is valid

(back to top)

Docs, secruity and deploy

logging

  • [] should i add? - to think about it

Create Docs

Security Packages

  • [] express-rate-limiter - is this needed?
  • helmet
  • xss-clean
  • cors (cookies!!!!)

Deploy on Heroku

  • heroku account and heroku cli
  • add dev command "nodemon app.js"
  • change start to "node app.js"
  • setup node version in package.json
  • git commit latest changes
  • heroku login
  • heroku create "App Name"
  • setup env vars in heroku
  • git push heroku

(back to top)

About

Boilerplate project for users authentication

Topics

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published