Skip to content

Authentication

STEP 1: USER VISITS LOGIN PAGE
─────────────────────────────────
GET /login
↓
getLogin controller executes
├─ Check req.session.userId exists?
│ ├─ YES → isLoggedIn = true
│ └─ NO → isLoggedIn = false
↓
Render login.ejs with isLoggedIn flag
↓
User sees login form
STEP 2: USER SUBMITS CREDENTIALS
─────────────────────────────────
POST /login (email + password in body)
↓
postLogin controller executes
├─ Query User table: WHERE email = req.body.email
│ ├─ NO MATCH → Log error, redirect /login
│ └─ MATCH → Proceed to password check
↓
Validate password: bcrypt.compare(req.body.password, user.password)
├─ FALSE → Password incorrect, redirect /login
└─ TRUE → Proceed to session creation
↓
Regenerate session (prevent session fixation)
req.session.regenerate((err) => { ... })
↓
Store userId in session
req.session.userId = user.id
↓
Save session to MySQL store
req.session.save((err) => { ... })
↓
Redirect to home (/)
res.redirect('/')
STEP 3: AUTHENTICATED USER MAKES REQUEST
──────────────────────────────────────────
GET / (or any route)
↓
Express-session middleware runs
├─ Read session cookie from browser
├─ Look up session in MySQL store
├─ Populate req.session.userId
└─ Pass control to next middleware
↓
App-level middleware (app.js line ~66)
↓
Check req.session.userId exists?
├─ YES → Fetch user from DB: User.findByPk(req.session.userId)
│ Cache in req.user object
│ Derive res.locals.isLoggedIn = true
│ Derive res.locals.isAdmin = user.isAdmin (from DB)
│ Pass res.locals.user = { id, name, email } to views
│
└─ NO → Set res.locals.user = null
Set res.locals.isLoggedIn = false
Set res.locals.isAdmin = false
↓
Route handler executes
(user data available in req.user for logic, res.locals for templates)
↓
If PUBLIC route (e.g., GET /) → Allow all users
↓
If PROTECTED route (e.g., /my/cart) → Check before executing
├─ res.locals.isLoggedIn === false?
│ └─ YES → Reject, redirect /login
└─ YES → Allow, execute handler
↓
If ADMIN route (e.g., /admin/write) → Check before executing
├─ res.locals.isAdmin === false?
│ └─ YES → Reject, redirect / (or 403 error)
└─ YES → Allow, execute handler
↓
Handler sends response
├─ EJS templates can access: user, isLoggedIn, isAdmin
└─ JSON APIs can access: req.user
↓
Browser receives response + session cookie (if modified, renewed)
STEP 4: USER LOGS OUT
──────────────────────
POST /logout (usually from button/form)
↓
postLogout controller executes
↓
Destroy session
req.session.destroy((err) => {
// Session removed from MySQL store
// Session cookie marked for deletion
})
↓
Redirect to home (/)
res.redirect('/')
↓
Browser deletes session cookie
↓
Next request
├─ req.session.userId = undefined
├─ User treated as anonymous
└─ res.locals.isLoggedIn = false, res.locals.isAdmin = false


STEP 5: SESSION EXPIRATION (BACKGROUND)
────────────────────────────────────────
Session maxAge timeout occurs
(e.g., 7 days set in app.js)
↓
express-mysql-session's cleanExpired job
(runs periodically, default every minute)
↓
Old sessions deleted from MySQL store
↓
User's next request has invalid session cookie
├─ Cookie points to non-existent session
├─ req.session.userId = undefined
└─ User auto-logged out
Want to print your doc?
This is not the way.
Try clicking the ··· in the right corner or using a keyboard shortcut (
CtrlP
) instead.