Password Management in Plings-Web — Design Spec
Password Management in Plings-Web — Design Spec
Created: Thu 11 Jun 2026 16:18:30 CEST Document Version: 1.0 - Initial design spec Security Classification: Internal Technical Documentation Target Audience: Frontend Developers Author: Paul Wisén
Problem
Two gaps in password handling today:
- Password reset via e-mail does not lead to a “set new password” step. The reset link signs the user in directly (recovery session) and lands on the home page, with no way to actually set a new password. A complete set-new-password page already exists at
/reset-password(src/pages/ResetPassword.tsx) but users never reach it, because:resetPasswordinsrc/contexts/AuthContext.tsxhardcodesredirectTo: 'https://plings.io/reset-password'(breaks local dev and preview deploys), and- the Supabase project’s Redirect URLs allowlist most likely does not include
/reset-password, so Supabase falls back to the Site URL (home page).
- No way to change the password inside the app. The
UserProfiledropdown has no account settings, and no settings page exists.
Decisions (from design discussion)
- In-app password change lives in a dialog opened from the profile dropdown (no settings page yet).
- No current-password requirement for the in-app change — users who signed up via e-mail verification may not have a usable password at all.
- After a successful reset via e-mail link, the user stays signed in and is taken to the dashboard (today’s code signs the user out and forces a fresh login).
Design
1. Recovery flow fix
AuthContext.resetPassword:redirectTobecomes`${window.location.origin}/reset-password`so the flow works in local dev, preview deploys, and production.- The existing
onAuthStateChangelistener inAuthContextadditionally handles thePASSWORD_RECOVERYevent by navigating to/reset-password(viawindow.location.assign, only if not already there). This is the safety net: even if Supabase falls back to the Site URL, the user is forced into the set-password form. - Supabase dashboard configuration (manual step): add to Auth → URL Configuration → Redirect URLs:
https://plings.io/reset-passwordhttp://localhost:8080/reset-password
2. ResetPassword page adjustments
- On success: no sign-out; show success toast and
navigate('/dashboard'). - Form and validation otherwise unchanged.
3. Shared component: PasswordFields
- New
src/components/auth/PasswordFields.tsx: new-password + confirm fields plus the live requirements checklist (min 8 chars, uppercase, lowercase, number, special character). ExportsvalidatePassword. ResetPassword.tsxis refactored to use it, so the page and the dialog share one validation implementation.
4. New component: ChangePasswordDialog
- New
src/components/auth/ChangePasswordDialog.tsx: shadcn dialog wrappingPasswordFields, callssupabase.auth.updateUser({ password }). - New “Change password” menu item (key icon) in the
UserProfiledropdown, between the e-mail row and Sign out. - Error handling: Supabase errors are shown inside the dialog (e.g. “New password should be different from the old password”); success shows a toast and closes the dialog.
5. Testing
Manual verification against the local dev server (no test runner exists in Plings-Web):
- Forgot password → e-mail → link → set new password → land signed-in on dashboard.
- Profile menu → Change password → new password works on next sign-in.
- Expired/invalid reset link shows an error and redirects home.
Future Work — Alternativ B: migrate to PKCE auth flow
Decided during design (2026-06-11): to be done later as its own effort.
Today the app uses Supabase’s implicit flow (tokens in the URL hash). Supabase’s recommended modern approach is PKCE (flowType: 'pkce' in the client config) with explicit code verification on the reset page (exchangeCodeForSession / verifyOtp with token_hash). Benefits: no tokens in URLs (safer with logging/history/referrers). Scope warning: switching affects all auth flows (sign-in, e-mail verification, password recovery) and needs end-to-end retesting of each — which is why it was split out of this work.