Skip to content

Conversation

@Darshan98Solanki
Copy link

@Darshan98Solanki Darshan98Solanki commented Nov 10, 2025

Hey @gorkemcetin,

Fixes #3010

Please ensure all items are checked off before requesting a review. "Checked off" means you need to add an "x" character between brackets so they turn into checkmarks.

  • (Do not skip this or your PR will be closed) I deployed the application locally.
  • (Do not skip this or your PR will be closed) I have performed a self-review and testing of my code.
  • I have included the issue # in the PR.
  • I have not included any files that are not related to my pull request, including package-lock and package-json if dependencies have not changed
  • I didn't use any hardcoded values (otherwise it will not scale, and will make it difficult to maintain consistency across the application).
  • I ran npm run format in server and client directories, which automatically formats your code.
  • I took a screenshot or a video and attached to this PR if there is a UI change.

I just have encoded the password before hit request (cause it is reserved keywords) and decode that on backend before validating and insert option in db.

Note:- from frontend we saw that password is there in payload but when we log password in backend we see empty string like ''. So this method I have added.

Have given the SS for validating the changed on real time.

Signup form:-
image

Login form:-
image

After login:-
image

Please check the pr and let me know is there is any updates.

Summary by CodeRabbit

  • Refactor
    • Updated authentication data handling to enhance password transmission security during register and login processes.

@coderabbitai
Copy link

coderabbitai bot commented Nov 10, 2025

Note

.coderabbit.yml has unrecognized properties

CodeRabbit is using all valid settings from your configuration. Unrecognized properties (listed below) have been ignored and may indicate typos or deprecated fields that can be removed.

⚠️ Parsing warnings (1)
Validation error: Unrecognized key(s) in object: 'release_notes'
⚙️ Configuration instructions
  • Please see the configuration documentation for more information.
  • You can also validate your configuration using the online YAML validator.
  • If your editor has YAML language server enabled, you can add the path at the top of this file to enable auto-completion and validation: # yaml-language-server: $schema=https://coderabbit.ai/integrations/schema.v2.json

Walkthrough

Client and server now synchronize password handling through URL encoding and decoding. The client encodes passwords via encodeURIComponent before transmission, and the server decodes them via decodeURIComponent upon receipt in both authentication endpoints, preserving special characters during transmission.

Changes

Cohort / File(s) Change Summary
Password URL encoding on client
client/src/Features/Auth/authSlice.js
Added encodeURIComponent to password before sending in both register and login thunks
Password URL decoding on server
server/src/controllers/v1/authController.js
Added decodeURIComponent to req.body.password in both registerUser and loginUser handlers prior to validation

Sequence Diagram

sequenceDiagram
    participant User
    participant Client as Client (authSlice.js)
    participant Network as HTTP Request
    participant Server as Server (authController.js)
    participant Validator

    User->>Client: Enter password with special chars (e.g., "<BIBpIiDXbgdp6M0vr6SO8T7")
    Client->>Client: encodeURIComponent(password)
    Client->>Network: Send encoded password
    Network->>Server: Receive encoded password
    Server->>Server: decodeURIComponent(req.body.password)
    Server->>Validator: Validate decoded password
    Validator-->>Server: ✓ Valid
    Server-->>Client: ✓ Success
    Client-->>User: Account created
Loading

Estimated code review effort

🎯 2 (Simple) | ⏱️ ~8 minutes

  • Homogeneous, repetitive pattern applied consistently across two files
  • No control flow changes or complex logic
  • Critical consideration: Verify that encoding/decoding roundtrip preserves all special characters without data loss
  • Confirm no other password handling paths bypass this encoding/decoding mechanism

Poem

A rabbit hops with glee, encoding as it goes,
The password wrapped in URL's protective throes,
Special chars like < now safely pass through space,
No more phantom empties—decoded with grace! 🐰✨

Pre-merge checks and finishing touches

✅ Passed checks (5 passed)
Check name Status Explanation
Title check ✅ Passed The title accurately describes the main fix: resolving signup errors when passwords contain reserved characters like '<>'.
Description check ✅ Passed The description includes issue reference, completed checklist items, clear explanation of the solution, and supporting screenshots for validation.
Linked Issues check ✅ Passed The PR code changes directly address issue #3010 by URL-encoding passwords client-side and decoding server-side, preventing '<' and other reserved characters from causing validation failures.
Out of Scope Changes check ✅ Passed Changes are limited to auth-related files (authSlice.js and authController.js) and directly target the password encoding issue without introducing unrelated modifications.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
✨ Finishing touches
  • 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (3)
server/src/controllers/v1/authController.js (1)

179-192: Password changes in editUser do not support special characters.

The editUser function accepts password and newPassword fields for password changes but does not decode them. Users who registered with special characters (like '<') will be unable to update their passwords to new values containing these characters, creating an inconsistent user experience.

Ensure the client encodes both password and newPassword fields in the update thunk (authSlice.js, lines 53-54), then decode them here:

 editUser = this.asyncHandler(
   async (req, res) => {
+    if (req.body.password) {
+      req.body.password = decodeURIComponent(req.body.password);
+    }
+    if (req.body.newPassword) {
+      req.body.newPassword = decodeURIComponent(req.body.newPassword);
+    }
     await editUserBodyValidation.validateAsync(req.body);
client/src/Features/Auth/authSlice.js (2)

53-54: Encode passwords in the update flow.

The password and newPassword fields are added to FormData without encoding, meaning users cannot change their passwords to values containing special characters like '<'. This creates an inconsistent experience where registration supports these characters but password updates do not.

Apply this diff:

-    form.password && fd.append("password", form.password);
-    form.newPassword && fd.append("newPassword", form.newPassword);
+    form.password && fd.append("password", encodeURIComponent(form.password));
+    form.newPassword && fd.append("newPassword", encodeURIComponent(form.newPassword));

120-122: Encode password in the recovery flow for consistency with other authentication flows.

The setNewPassword thunk does not encode the password, while both login and register thunks use encodeURIComponent() on the password field. This inconsistency should be addressed.

+ const encodedForm = { 
+   ...form, 
+   password: form.password ? encodeURIComponent(form.password) : form.password 
+ };
  const res = await networkService.setNewPassword({
    recoveryToken: token,
-   form: form,
+   form: encodedForm,
  });
📜 Review details

Configuration used: Path: .coderabbit.yml

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 7cb9851 and 424b991.

📒 Files selected for processing (2)
  • client/src/Features/Auth/authSlice.js (2 hunks)
  • server/src/controllers/v1/authController.js (2 hunks)
🔇 Additional comments (3)
client/src/Features/Auth/authSlice.js (1)

15-16: LGTM! Password encoding implemented correctly.

The password is properly encoded using encodeURIComponent before transmission, and the original form object is preserved by creating a new reqObj. This approach correctly addresses the issue where special characters like '<' caused validation failures.

Also applies to: 32-33

server/src/controllers/v1/authController.js (2)

461-477: The review comment is incorrect and should be dismissed.

The password handling across endpoints is actually consistent and intentional:

  • Public endpoints (register, login): Client encodes password → Server decodes it
  • Authenticated endpoints (password change, admin reset, password recovery): No encoding on either side

This design is sound because authenticated endpoints transmit over HTTPS with JWT authentication, making URL encoding unnecessary. The encoding in public endpoints adds an extra layer for form submission.

The editUserPasswordById endpoint correctly follows the authenticated endpoint pattern—it matches resetPassword and the user's own password change flow. There is no inconsistency to fix.

Likely an incorrect or invalid review comment.


300-311: The original review comment is incorrect—special characters are supported in password recovery.

The resetPassword endpoint will successfully handle special characters like '<' because the password flows through without encoding/decoding and is validated as-is. While register and login use an encode/decode pattern, and resetPassword passes the password directly, both approaches validate the same passwordPattern against the raw character, so the end result is functionally equivalent. No fix is required.

Likely an incorrect or invalid review comment.

if (req.body?.email) {
req.body.email = req.body.email?.toLowerCase();
}
req.body.password = decodeURIComponent(req.body.password);
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

Add null/undefined check before decoding the password.

If req.body.password is undefined or null, decodeURIComponent will convert it to the string "undefined" or "null", which may bypass Joi validation for required fields.

Apply this defensive pattern:

+if (req.body.password) {
   req.body.password = decodeURIComponent(req.body.password);
+}

Apply the same fix on line 131 in loginUser.

Also applies to: 131-131

🤖 Prompt for AI Agents
In server/src/controllers/v1/authController.js around lines 94 and 131, the code
unconditionally calls decodeURIComponent on req.body.password which will coerce
null/undefined to the strings "null"/"undefined" and can bypass Joi required
checks; update both places to first verify the password is a non-empty string
(e.g., typeof req.body.password === 'string' and req.body.password !== '')
before calling decodeURIComponent, otherwise leave it as undefined or null so
validation fails properly.

Copy link

@llamapreview llamapreview bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

AI Code Review by LlamaPReview

🎯 TL;DR & Recommendation

Recommendation: Request Changes

This PR fixes a password validation bug but introduces a critical client-server coupling and a security vulnerability by decoding user input before validation.

🌟 Strengths

  • Successfully resolves the reported issue where passwords containing '<' characters were incorrectly rejected.
Priority File Category Impact Summary Anchors
P1 client/src/Features/Auth/authSlice.js Architecture Client-server coupling risks breaking future client apps
P1 server/.../authController.js Security Decoding before validation risks bypassing security checks
P2 server/.../authController.js Maintainability Duplicated code increases maintenance risk
P2 client/src/Features/Auth/authSlice.js Testing Missing tests risk undetected regressions

🔍 Notable Themes

  • The encoding/decoding workaround introduces systemic coupling and security risks instead of addressing the root cause in the sanitization middleware.

📈 Risk Diagram

This diagram illustrates the new password encoding/decoding flow and its associated security and coupling risks.

sequenceDiagram
    participant C as Client
    participant AC as Auth Controller
    participant US as User Service
    C->>AC: POST /register (password encoded)
    note over AC: R2(P1): Decodes before validation,<br/>risks security bypass
    AC->>US: registerUser(decoded password)
    note over C,AC: R1(P1): Tight coupling requires<br/>all clients to encode
Loading

💡 Have feedback? We'd love to hear it in our GitHub Discussions.
✨ This review was generated by LlamaPReview Advanced, which is free for all open-source projects. Learn more.

Comment on lines 13 to 17
export const register = createAsyncThunk("auth/register", async (form, thunkApi) => {
try {
const res = await networkService.registerUser(form);
const reqObj = { ...form, password: encodeURIComponent(form.password) };
const res = await networkService.registerUser(reqObj);
return res.data;
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 | Confidence: High

This change introduces a client-side encoding dependency that creates a tight coupling between client and server implementations. The client now assumes the server will decode passwords, making the API contract implicit rather than explicit. This breaks the principle of separation of concerns - password encoding/decoding should be handled consistently on the server side where security logic belongs. Any future client implementation (mobile app, CLI) must replicate this encoding logic or authentication will fail.

Code Suggestion:

Remove client-side encoding and fix the root cause in server-side sanitization middleware.

P2 | Confidence: Medium

Speculative: The PR description shows manual testing but doesn't mention automated tests. Password encoding/decoding is critical security functionality that should have unit tests covering edge cases (special characters, malformed encoding, empty passwords). Without tests, regressions could go undetected.

Code Suggestion:

Add unit tests for authSlice encoding and authController decoding with various special character combinations.

*/
registerUser = this.asyncHandler(
async (req, res) => {
if (req.body?.email) {
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[Contextual Comment]
This comment refers to code near real line 89. Anchored to nearest_changed(91) line 91.


P1 | Confidence: High

This introduces a security vulnerability by decoding user input before validation. If an attacker sends URL-encoded malicious content, it will be decoded and then validated, potentially bypassing security checks. The validation schema expects raw password input, but now receives decoded content, creating inconsistency. Additionally, decodeURIComponent will throw on malformed URI components, potentially causing server errors.

Code Suggestion:

Remove server-side decoding and instead configure the sanitization middleware to exclude password fields or use proper escaping rather than removal.

*/
loginUser = this.asyncHandler(
async (req, res) => {
if (req.body?.email) {
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[Contextual Comment]
This comment refers to code near real line 126. Anchored to nearest_changed(128) line 128.


P2 | Confidence: High

The same decoding logic is duplicated in both register and login methods, violating DRY principles. Any future changes to password handling must be made in multiple places, increasing maintenance burden and risk of inconsistencies.

Code Suggestion:

Extract password decoding (if kept) into a shared middleware or utility function used by both endpoints.

@ajhollid
Copy link
Collaborator

ajhollid commented Nov 10, 2025

Hey @Darshan98Solanki ,

While it works, this seems like an overly complex solution to the problem.

Moreover, it creates a tight dependency between the front and back ends, which is to be avoided.

Is there some reason the validation on the frontend can't be modified to allow for the password in question?

@Darshan98Solanki
Copy link
Author

hey, @ajhollid

I understood your concern give me some time I will find some solution with decoupled for same.

@Owaiseimdad
Copy link
Contributor

Hey @Darshan98Solanki ,

While it works, this seems like an overly complex solution to the problem.

Moreover, it creates a tight dependency between the front and back ends, which is to be avoided.

Is there some reason the validation on the frontend can't be modified to allow for the password in question?

I think we need to think in terms of regex here, let me know what solution you have thought of.

@Darshan98Solanki
Copy link
Author

@ajhollid @Owaiseimdad

can we restrict < > this two letter for password or else pass the payload with stringify version but that is also tightly coupled.

I think restrict this letter will be good solution ?

@ajhollid
Copy link
Collaborator

@ajhollid @Owaiseimdad

can we restrict < > this two letter for password or else pass the payload with stringify version but that is also tightly coupled.

I think restrict this letter will be good solution ?

Stringifying or otherwise transforming the input defeats the purpose of input validation, so let's avoid that.

The input vaidation schema should be modified to allow for the < and > characters. Regex is probably a reasonable solution as @Owaiseimdad mentioned, why not give that a shot?

@Darshan98Solanki
Copy link
Author

New Regex:- /^(?=.[a-z])(?=.[A-Z])(?=.\d)(?=.[!?@#$%^&*()-_=+[]{};:'",.~|\\/])[A-Za-z\d!?@#$%^&*()\-_=+\[\]{};:'",.~|\/]{8,}$/;

Old Regex:- /^(?=.[a-z])(?=.[A-Z])(?=.[0-9])(?=.[!?@#$%^&*()-_=+[]{};:'",.<>~|\\/])[A-Za-z0-9!?@#$%^&*()\-_=+[\]{};:'",.<>~|\/]+$/;

Difference Note :-

  •     More secure (blocks < and >)
    
  •     Stronger (minimum 8 characters)
    

I think this regex is good for validation should I change this for validation of password ?
please give me you feedback @ajhollid @Owaiseimdad

@Darshan98Solanki
Copy link
Author

@ajhollid @Owaiseimdad @gorkemcetin

as per we discussed last any inputs ? should I remove <> sign from the password regex to prevent XXS attack and make it more secure also change the frontend relevant if needed.

@Darshan98Solanki
Copy link
Author

@ajhollid @Owaiseimdad @gorkemcetin

i'm looking inputs from your what should do further?

@ajhollid
Copy link
Collaborator

@Darshan98Solanki the new regex must be only more premissive than the original one, it cannot be any more restrictive or it could possibly disallow existing users. So you can remove the min 8 char and it should be good to go.

@Darshan98Solanki
Copy link
Author

@ajhollid
we also need to change the frontend as well. and give the list of special char list so the user will have clear idea about it.

@gorkem-bwl
Copy link
Contributor

@ajhollid we also need to change the frontend as well. and give the list of special char list so the user will have clear idea about it.

We can do that in another PR.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

'Password cannot be empty' user signup bug on fresh install

4 participants