Overview
The Resume Generator uses a secure JWT-based authentication system with HTTP-only cookies for session management. The system includes user registration, login/logout flows, token blacklisting for secure logout, and middleware-based route protection.
Authentication Flow
User Registration
New users register with a username, email, and password. Passwords are hashed using bcrypt before storage.
API Endpoint: POST /api/auth/register
Request Body:
{
"username" : "johndoe" ,
"email" : "[email protected] " ,
"password" : "securePassword123"
}
Backend Flow:
The registration controller validates input, checks for existing users, hashes the password, and creates a new user account:
async function registerUserController ( req , res ) {
const { username , email , password } = req . body
if ( ! username || ! email || ! password ) {
return res . status ( 400 ). json ({
message: "Please provide username, email and password"
})
}
const isUserAlreadyExists = await userModel . findOne ({
$or: [ { username }, { email } ]
})
if ( isUserAlreadyExists ) {
return res . status ( 400 ). json ({
message: "Account already exists with this email address or username"
})
}
const hash = await bcrypt . hash ( password , 10 )
const user = await userModel . create ({
username ,
email ,
password: hash
})
const token = jwt . sign (
{ id: user . _id , username: user . username },
process . env . JWT_SECRET ,
{ expiresIn: "1d" }
)
res . cookie ( "token" , token )
res . status ( 201 ). json ({
message: "User registered successfully" ,
user: {
id: user . _id ,
username: user . username ,
email: user . email
}
})
}
After successful registration, a JWT token is automatically generated and set as an HTTP-only cookie, logging the user in immediately.
User Login
Existing users authenticate with their email and password.
API Endpoint: POST /api/auth/login
Request Body:
Backend Flow:
The login controller validates credentials and issues a JWT token:
auth.controller.js:65-100
async function loginUserController ( req , res ) {
const { email , password } = req . body
const user = await userModel . findOne ({ email })
if ( ! user ) {
return res . status ( 400 ). json ({
message: "Invalid email or password"
})
}
const isPasswordValid = await bcrypt . compare ( password , user . password )
if ( ! isPasswordValid ) {
return res . status ( 400 ). json ({
message: "Invalid email or password"
})
}
const token = jwt . sign (
{ id: user . _id , username: user . username },
process . env . JWT_SECRET ,
{ expiresIn: "1d" }
)
res . cookie ( "token" , token )
res . status ( 200 ). json ({
message: "User loggedIn successfully." ,
user: {
id: user . _id ,
username: user . username ,
email: user . email
}
})
}
User Logout
Secure logout with token blacklisting prevents reuse of expired tokens.
API Endpoint: GET /api/auth/logout
Backend Flow:
The logout controller adds the current token to a blacklist and clears the cookie:
auth.controller.js:108-120
async function logoutUserController ( req , res ) {
const token = req . cookies . token
if ( token ) {
await tokenBlacklistModel . create ({ token })
}
res . clearCookie ( "token" )
res . status ( 200 ). json ({
message: "User logged out successfully"
})
}
Blacklisted tokens are stored in the database to prevent token reuse even before expiration. The auth middleware checks against this blacklist on every protected request.
User Interface Flows
Registration Page
The registration form collects username, email, and password from new users:
User Experience
Frontend Code
User navigates to /register
Fills in username, email, and password fields
Clicks “Register” button
On success, automatically redirected to home page (/) as authenticated user
Loading state displayed during registration
const handleSubmit = async ( e ) => {
e . preventDefault ()
await handleRegister ({ username , email , password })
navigate ( "/" )
}
Login Page
Existing users authenticate through the login form:
User Experience
Frontend Code
User navigates to /login
Enters email and password
Clicks “Login” button
On success, redirected to home page (/)
Link to registration page for new users
const handleSubmit = async ( e ) => {
e . preventDefault ()
await handleLogin ({ email , password })
navigate ( '/' )
}
Authentication Middleware
Protected routes use the authUser middleware to verify JWT tokens and check the blacklist:
async function authUser ( req , res , next ) {
const token = req . cookies . token
if ( ! token ) {
return res . status ( 401 ). json ({
message: "Token not provided."
})
}
const isTokenBlacklisted = await tokenBlacklistModel . findOne ({
token
})
if ( isTokenBlacklisted ) {
return res . status ( 401 ). json ({
message: "token is invalid"
})
}
try {
const decoded = jwt . verify ( token , process . env . JWT_SECRET )
req . user = decoded
next ()
} catch ( err ) {
return res . status ( 401 ). json ({
message: "Invalid token."
})
}
}
Middleware validates:
Token exists in cookies
Token is not blacklisted
Token signature is valid
Token is not expired
Data Models
User Schema
const userSchema = new mongoose . Schema ({
username: {
type: String ,
unique: [ true , "username already taken" ],
required: true ,
},
email: {
type: String ,
unique: [ true , "Account already exists with this email address" ],
required: true ,
},
password: {
type: String ,
required: true
}
})
Token Blacklist Schema
const blacklistTokenSchema = new mongoose . Schema ({
token: {
type: String ,
required: [ true , "token is required to be added in blacklist" ]
}
}, {
timestamps: true
})
Protected Routes
Routes that require authentication use the authUser middleware:
authRouter . get ( "/get-me" , authMiddleware . authUser , authController . getMeController )
Examples of protected endpoints:
GET /api/auth/get-me - Get current user details
POST /api/interview/ - Generate interview report
GET /api/interview/ - Get all user’s interview reports
POST /api/interview/resume/pdf/:interviewReportId - Generate resume PDF
Security Features
Password Hashing Passwords are hashed with bcrypt (10 rounds) before database storage
HTTP-Only Cookies JWT tokens stored in HTTP-only cookies prevent XSS attacks
Token Blacklisting Logged-out tokens are blacklisted to prevent reuse
Token Expiration JWT tokens expire after 24 hours (1 day)
Get Current User
Authenticated users can retrieve their profile information:
API Endpoint: GET /api/auth/get-me
Requires: Valid JWT token in cookies
Response:
{
"message" : "User details fetched successfully" ,
"user" : {
"id" : "507f1f77bcf86cd799439011" ,
"username" : "johndoe" ,
"email" : "[email protected] "
}
}
The password hash is never returned in API responses for security.