Skip to content

Comments

Change password#1558

Open
Andrew-Ryer wants to merge 43 commits intoOpenEnergyDashboard:developmentfrom
natetowsley:change_password
Open

Change password#1558
Andrew-Ryer wants to merge 43 commits intoOpenEnergyDashboard:developmentfrom
natetowsley:change_password

Conversation

@Andrew-Ryer
Copy link

@Andrew-Ryer Andrew-Ryer commented Nov 28, 2025

Description

This PR implements the full User Password Change feature in OED, enabling any authenticated user to securely change their own password via the Options → Change Password menu, without admin intervention. The work spans backend API, frontend RTK Query integration, a new modal UI component, and integration into the main application with translations.

On the backend, it adds a new POST /api/users/changePassword endpoint protected by authentication middleware that verifies the user’s JWT, validates input (including length constraints), confirms the current password with bcrypt.compare, securely hashes the new password with bcrypt.hash, and updates the database via User.updateUserPassword. On the frontend, it introduces a changePassword RTK Query mutation and a ChangePasswordModal React component that displays the current username, collects current/new/confirm password, performs real-time validation, and shows success/error notifications. The feature is fully integrated into HeaderButtonsComponent via a “Change Password” entry in the Options dropdown and wired into the translations system so all UI text is available in English, French, and Spanish.

Fixes #1526 - Allow each user to change password

Type of change

(Check the ones that apply by placing an "x" instead of the space in the [ ] so it becomes [x])

  • Note merging this changes the database configuration.
  • This change requires a documentation update

Checklist

(Note what you have done by placing an "x" instead of the space in the [ ] so it becomes [x]. It is hoped you do all of them.)

  • I have followed the OED pull request ideas
  • I have removed text in ( ) from the issue request
  • You acknowledge that every person contributing to this work has signed the OED Contributing License Agreement and each author is listed in the Description section.

Limitations

  • Password policy is limited to length-based validation (8–128 characters); there is no password strength meter or enforcement of complexity (e.g., symbols, digits, upper/lowercase mix).
  • Password history / reuse prevention is not implemented; users can technically reuse previous passwords as long as they meet length requirements.
  • No rate-limiting or lockout mechanism is added specifically for the password change endpoint; it relies on existing global protections.
  • Automated tests (unit/integration/e2e) for the new endpoint, RTK Query mutation, and modal component are not included as part of this PR; verification has been described and performed manually and could be formalized in follow-up test work.
  • Documentation and user-facing help text about the new “Change Password” option in the OED UI are not included and can be added in a separate documentation update if desired.

Contributors:
Andrew Ryer — @Andrew-Ryeraryer@csumb.edu
Nathan Towsley — @natetowsleynatetowsley@gmail.com
Tyler Herndon — @GoKartMan89tylerherndon89@gmail.com
Caleb Stark — @caleb-starkstark.caleba@gmail.com

natetowsley and others added 28 commits November 10, 2025 13:05
…ranslations for "change.password" to data.ts
…o allow for the showing of more than one kind of modal. Adjusted handleClose() and handleShow() accordingly. Added a modalType to login modal and created a copy with modalType 'changePassword' as placeholder.
…alType to allow for the showing of more than one kind of modal. Adjusted handleClose() and handleShow() accordingly. Added a modalType to login modal and created a copy with modalType 'changePassword' as placeholder."

This reverts commit c20bec1.
….ts, correct modal now shows when clicking change password.
Co-authored-by: GoKartMan89 <tylerherndon89@gmail.com>
Co-authored-by: caleb-stark <stark.caleba@gmail.com>
Co-authored-by: Andrew-Ryer <aryer@csumb.edu>
Copy link
Member

@huss huss left a comment

Choose a reason for hiding this comment

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

Thanks to @Andrew-Ryer, @natetowsley, @GoKartMan89 & @caleb-stark for this contribution to OED. I'm sorry it took about a week to get back to you. Overall, it works well. I have made some comments to consider. Please let me know if anything is not clear or I can help.

@natetowsley
Copy link

@huss Changes addressed. Please let us know if there's anything else we should do.

- The messages are also displayed to the user.
- Changes information returned to mask info for security
reasons. Also logs more info for security.
- Minor changes in message wording for translation.
- Minor formatting changes.
Copy link
Member

@huss huss left a comment

Choose a reason for hiding this comment

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

Thanks to @Andrew-Ryer, @natetowsley, @GoKartMan89 & @caleb-stark for the updated code to address my previous comments. There are a couple of old comments that I thought should still be addressed and I added to the comment chain. I also pushed a commit to use success/failure since you indicated issues in getting it to work. It also includes other changes to address ongoing security work that was not part of what you were doing. I would welcome you looking at the code to see if you think it is correct/appropriate and verifying it works as desired. Please let me know if anything is not clear or I can help.

@huss
Copy link
Member

huss commented Dec 12, 2025

For unknown reasons my recent comments are showing up twice. I'm just going to leave them to avoid any more issues. Sorry.

@huss
Copy link
Member

huss commented Jan 13, 2026

@Andrew-Ryer, @natetowsley, @GoKartMan89 & @caleb-stark It has been about a month since my last comments. I think this is close to complete so I wanted to know the current status. Thanks.

@natetowsley
Copy link

@huss Apologies, I think all of us lost this is the midst of the school semester ending and the holidays coming around. I will have your changes addressed within the next week. Hope your holiday season went well.

@natetowsley
Copy link

Changes addressed @huss

Copy link
Member

@huss huss left a comment

Choose a reason for hiding this comment

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

Thanks to @Andrew-Ryer, @natetowsley, @GoKartMan89 & @caleb-stark for addressing the previous comments. I'm sorry it took a little while for me to look at this. It is working very well. I've made a few comments but I think they are all simple to do and then this should be ready to merge. Please let me know if you have thoughts or need anything.

<Col>
<FormGroup>
<Label for='currentPassword'>
{translate('current.password')}
Copy link
Member

Choose a reason for hiding this comment

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

Should this now be password.current?

id='currentPassword'
name='currentPassword'
type='password'
placeholder={translate('password.current.enter')}
Copy link
Member

Choose a reason for hiding this comment

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

I think this placeholder should be removed. The user creation page and other OED pages do no do this. The title is what OED uses to consistently indicate what to put in the box/item below it. The title is fine here. I also have comments in data.ts about the strings. The same applies to the other two inputs. I'm sorry I did not catch this earlier.

"password.confirm": "Confirm password: ",
"password.confirm.enter": "Confirm new password",
"password.current": "Current password",
"password.current.enter": "Enter current password",
Copy link
Member

Choose a reason for hiding this comment

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

This key can be removed in all languages. Note all changes to items should be done in all languages but I'm only noting that here.

"password.change": "Change password",
"password.confirm": "Confirm password: ",
"password.confirm.enter": "Confirm new password",
"password.current": "Current password",
Copy link
Member

Choose a reason for hiding this comment

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

Please put a colon (:) at the end so it is consistent with other titles.

"page.user.refresh.directions": "If clicking the \"Return to Dashboard\" button does not work then please click the button below to restart your OED session",
"password": "Password: ",
"password.change": "Change password",
"password.confirm": "Confirm password: ",
Copy link
Member

Choose a reason for hiding this comment

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

I think this would be better as "Confirm new password" (as the enter had but note there is no trailing space) so it is very clear and parallel to "Current password". The next key can be removed.

Choose a reason for hiding this comment

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

"Change Password" is only used for the button in the menu I feel like it would be confusing to change it to "Confirm new Password" was this just a mistake you you meant to change "Confirm password" to "Confirm new password" i think it would involve a new key because confirm password is used in files separate from ours

Copy link
Member

Choose a reason for hiding this comment

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

Sorry for the delay in getting to this and that my comment was confusing. In another comment I suggested changing from "Password" to "New password". In the same way I was thinking to add "new" here so it is parallel on the web page. I also agree that it is only for that place on the web page so a new key may be needed. Does this help?

"password.current": "Current password",
"password.current.enter": "Enter current password",
"password.failed.to.change": "Failed to change password with response: ",
"password.new.enter": "Enter new password",
Copy link
Member

Choose a reason for hiding this comment

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

This key can go.

<Col>
<FormGroup>
<Label for='newPassword'>
{translate('password')}
Copy link
Member

Choose a reason for hiding this comment

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

I think this string should be "New password:" so it is very clear and consistent with other ones. This probably requires a new key in data.ts.

const passwordModified = passwordDetails.currentPassword.length > 0 ||
passwordDetails.newPassword.length > 0 ||
passwordDetails.confirmPassword.length > 0;

Copy link
Member

Choose a reason for hiding this comment

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

This file has a number of formatting issues. If you do 'format document' in VSC they should all go away. Please let me know if you need any help with this.

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.

Allow each user to change password

5 participants