At first glance, the implementation looked secure. The application was using httpOnly cookies to store both the accessToken and refreshToken, which is a common and recommended approach.
However, while inspecting the response, I noticed that the same tokens were also being returned inside the JSON body.
Understanding the Flow
The login process works as expected:
- User submits email and password
- Backend validates the credentials
- Generates accessToken and refreshToken
- Stores them in httpOnly cookies
This is generally considered a secure design.
Looking at the Code
const { accessToken, refreshToken } = await generateAccessAndRefreshTokens(
user._id,
);
const options = {
httpOnly: true,
secure: true,
};The tokens are stored securely in cookies.
Up to this point, everything looks correct.
The Vulnerable Code
The issue appears in the response handling:
return res
.status(200)
.cookie("accessToken", accessToken, options)
.cookie("refreshToken", refreshToken, options)
.json({
user: loggedInUser,
accessToken: accessToken,
refreshToken: refreshToken,
message: "User logged in successfully",
});The same tokens that are stored in httpOnly cookies are also returned in the JSON response.
Why This Is a Problem
The purpose of httpOnly cookies is to prevent JavaScript from accessing sensitive tokens.
But in this case:
- The tokens are already exposed in the response body
- Any JavaScript (for example via XSS) can access them
This completely removes the protection provided by httpOnly.
Proof of the Issue

The response clearly includes both tokens.
Impact
This can lead to:
- Token leakage
- Session hijacking
- Account takeover
- This effectively turns a secure cookie-based auth system into a client-exposed token system.
If an attacker is able to exploit even a simple XSS vulnerability, they can easily extract these tokens.
A small mistake like this is enough to expose sensitive tokens despite using httpOnly cookies.
It's not a complex bug, just a small logic mistake that leads to token exposure.
Fixing the Issue
The fix is straightforward.
Do not include sensitive tokens in the JSON response if they are already handled using httpOnly cookies.
return res
.status(200)
.cookie("accessToken", accessToken, options)
.cookie("refreshToken", refreshToken, options)
.json({
user: loggedInUser,
message: "User logged in successfully",
});After Fix

After removing the tokens from the response, they are no longer accessible from the client-side JavaScript.
Final Thought
The implementation looked secure at first, but a small mistake in the response completely broke the protection.
Security is not only about using the right mechanisms, but also about using them correctly.