Skip to content

fix(auth): align the client password rule with the server — Closes #270 - #486

Merged
SRV30 merged 1 commit into
SRV30:mainfrom
SakethSumanBathini:fix/password-special-char-mismatch
Aug 10, 2026
Merged

fix(auth): align the client password rule with the server — Closes #270#486
SRV30 merged 1 commit into
SRV30:mainfrom
SakethSumanBathini:fix/password-special-char-mismatch

Conversation

@SakethSumanBathini

Copy link
Copy Markdown
Contributor

Closes #270

The two rules disagree

Client, in three separate files:

/[!@#$%^&*(),.?":{}|<>]/

Server, server/validators/authSchemas.js:13:

.regex(/[^A-Za-z0-9]/, "Password must contain at least one special character")

The client's allow-list is narrower. Thirteen characters the API accepts are rejected by the browser:

'  +  -  /  ;  =  [  \  ]  _  `  ~  and space
My_Pass1     client=REJECTED  server=ok
Passw0rd-    client=REJECTED  server=ok
Pa55word+    client=REJECTED  server=ok
Secure~1     client=REJECTED  server=ok

The underscore and the hyphen are the ones that matter — both are common in real passwords, and a password manager will happily generate either.

Why it is worse than a cosmetic mismatch

The client does not just hint. Signup.jsx:34 blocks submission:

const isAllRequirementsMet = passwordRequirements.every((req) => req.test(password));
if (!isAllRequirementsMet) {
  toast.error("Password does not meet complexity requirements!");
  return;
}

So a user typing My_Pass1 is stopped, and told their password is not complex enough — when the server would have accepted it. There is nothing on screen to suggest which character is the problem, because the checklist item just says "Special character" and stays unticked.

It was in three files, not one

Signup.jsx, ResetPassword.jsx and UpdatePassword.jsx each carried their own copy of the same five rules. All three had the narrow version, so the bug appears at signup, at password reset, and at password change.

That duplication is also how the drift happened: the server rule changed and three copies did not follow.

The change

One shared module, client/src/utils/passwordRequirements.js, imported by all three. The special-character rule now matches the server exactly:

test: (pw) => /[^A-Za-z0-9]/.test(pw)

Written as a negated class rather than a longer allow-list deliberately. An allow-list has to be kept in step with the server by hand, which is the thing that failed here. A negated class is the same expression the server uses, so the two cannot disagree without someone changing both.

The label is now Special character (e.g. ! @ # _ - ?) — the previous "Special character" gave no clue that _ counted, and the examples include the two characters that were being rejected.

The other four rules are unchanged.

Verified

Client and server agree on every case:

password       client   server   agree
My_Pass1       true     true     yes
Passw0rd-      true     true     yes
Pa55word+      true     true     yes
Secure~1       true     true     yes
Test[1]a       true     true     yes
Good/Pass1     true     true     yes
Str0ng!Pw      true     true     yes
NoSpecial1     false    false    yes

NoSpecial1 is the control — a password with no special character is still refused by both, so this loosens the rule to match the server rather than removing it.

All four files parse under esbuild.

One thing I could not verify

npm run build fails on this repository, on a clean checkout of main as well as on this branch:

[vite]: Rolldown failed to resolve import "@stripe/stripe-js" from "client/src/pages/Checkout.jsx"

@stripe/stripe-js is imported but is not in client/package.json. I confirmed this by stashing my changes and building main — the failure is identical, so it is unrelated to this PR, but it does mean I could not get a full build to pass. Worth its own issue.

@vercel

vercel Bot commented Aug 10, 2026

Copy link
Copy Markdown

@SakethSumanBathini is attempting to deploy a commit to the srv30's projects Team on Vercel.

A member of the Team first needs to authorize it.

@SRV30 SRV30 added elusoc Official ELUSOC 2026 issue. Contributions on these issues are eligible for ELUSOC participation. newbie Beginner-friendly tasks suitable for first-time contributors. (10 XP) labels Aug 10, 2026
@SRV30
SRV30 merged commit f1c484d into SRV30:main Aug 10, 2026
5 of 12 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

elusoc Official ELUSOC 2026 issue. Contributions on these issues are eligible for ELUSOC participation. newbie Beginner-friendly tasks suitable for first-time contributors. (10 XP)

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[BUG] Signup fails with repeated "Server error. Please try again." toasts stacking up

2 participants