feat: let staff force a password reset without emailing a link - #23
Merged
Conversation
Adds a staff-triggered "force password reset" toggle for managed users, companion to the isPasswordReset login-lockout fix merged in PR #22. Previously isPasswordReset could only be set at seed time or via the existing "send reset email" flow (Users.bx#resetPassword(), which emails a link the user must click). There was no way for an admin to force an existing user to change their password on their very next login without waiting on that email. - Users.bx#forcePasswordReset(): sets isPasswordReset=true directly (no email), guarded by @secured("users:admin"), CSRF-checked like the handler's other mutating actions, and blocked against self-targeting via the existing ensureNotSelf() helper. Now that the login flow (PR #22) checks isPasswordReset and redirects a correct-password login into the reset-password flow, this takes effect on the user's very next login. - Router.bx: POST users/:userId/force-password-reset - users/detail.bxm: a "Force password reset" row next to the existing "Send reset email" row, disabled once already pending. - UserDetailForm.js: forcePasswordReset() action, mirroring the existing resetPassword()/verifyUser() actions. No dedicated test added: this repo has no handler-level test coverage for any of Users.bx's existing sibling actions (setStatus, resetPassword, verify, etc.), so this follows that precedent. Verified via `npm run build` and `npm run lint` (clean on the changed file); the underlying isPasswordReset-triggers-a-redirect behavior is already covered by AuthTest.bx from PR #22. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Ft3NTvnLUZ99axxmLn6Cxf
Test Results145 tests 145 ✅ 10s ⏱️ Results for commit 0fe6958. ♻️ This comment has been updated with latest results. |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Description
Companion feature to #22 (merged): a staff-triggered "force password reset" toggle for managed users.
Previously
isPasswordResetcould only be set at seed time (a freshly-seeded admin) or via the existing "send reset email" flow (Users.bx#resetPassword()), which emails a link the user must click. There was no way for an admin to force an existing user to change their password on their very next login without waiting on that email.What this adds:
Users.bx#forcePasswordReset()— a new@secured("users:admin")action that setsisPasswordReset=truedirectly (no email sent), guarded by CSRF like the handler's other mutating actions, and blocked against self-targeting via the existingensureNotSelf()helper. Audit-logged via the existingauditLogService, matching the pattern ofsetStatus()/verify().Router.bx:POST users/:userId/force-password-resetusers/detail.bxm: a new "Force password reset" row next to the existing "Send reset email" row in the Security tab, disabled once already pending (Already required on next login.).UserDetailForm.js: aforcePasswordReset()Alpine action mirroring the existingresetPassword()/verifyUser()actions.Since the login flow (#22) already checks
isPasswordResetand redirects a correct-password login into the reset-password flow instead of the dashboard, this toggle takes effect on the targeted user's very next login attempt — no separate wiring needed on that side.Verification
npm run build— clean.npm run lint— clean on the changed file (UserDetailForm.js); pre-existing lint errors in an unrelated file,AuditLogForm.js, are untouched by this PR.Users.bx's existing sibling actions (setStatus,resetPassword,verify, etc.), so this follows that precedent rather than introducing a one-off pattern.box installcan't fetch ColdBox/TestBox here). The underlying "a correct password on anisPasswordResetaccount redirects to the reset-password flow instead of the dashboard" behavior is already covered end-to-end byAuthTest.bxfrom fix: isPasswordReset locks users out of login instead of forcing a reset #22, which passed 145/145 in CI on that PR. This toggle only flips the same flag through a new admin-facing entry point, so no new server-side behavior needs separate coverage beyond that existing test — CI will confirm nothing regressed.Issues
No existing tracked issue — ported from an equivalent feature already built and running in a downstream app (bx-sites-cloud) that was scaffolded from this template, adapted to this repo's actual
Users.bx/detail.bxm/UserDetailForm.jsstructure (confirmed to already have thegetManagedUser()/ensureNotSelf()/buildDetailPayload()/auditLogServicehelpers this feature relies on).Type of change
Checklist
forcePasswordReset()explains how it differs fromresetPassword()and how it interacts with the login flow from fix: isPasswordReset locks users out of login instead of forcing a reset #22)🤖 Generated with Claude Code
https://claude.ai/code/session_01Ft3NTvnLUZ99axxmLn6Cxf
Generated by Claude Code