Ustawianie i resetowanie hasła
Wszystkie ścieżki, w których klient dostaje mailem link do ustawienia hasła: zaproszenie do nowego konta, konto bez hasła (rejestracja przez SMS lub Google) oraz zwykłe „nie pamiętam hasła".
👤 Instrukcja dla klienta
Konto założone przez klub
Po założeniu konta przez pracownika klient dostaje maila „Ustaw hasło do swojego konta". W środku jest przycisk Ustaw hasło, a pod nim ten sam link w postaci tekstowej — do skopiowania, gdy klient czyta pocztę w programie, który blokuje przyciski. Link jest ważny 24 godziny.
Konto bez hasła (rejestracja przez telefon lub Google)
Klient wpisuje na /auth/login swój adres e-mail i klika Kontynuuj. Jeśli
konto nie ma jeszcze własnego hasła, system od razu wysyła maila z linkiem i
pokazuje ekran „Sprawdź skrzynkę". Gdy wysyłka się nie uda, ekran mówi o tym
wprost i proponuje ponowienie (przycisk odblokowuje się po 60 sekundach) albo
logowanie numerem telefonu lub kontem Google.
Nie pamiętam hasła
Link „Nie pamiętasz hasła?" prowadzi na /auth/recover. Klient wybiera
kanał:
- Kod SMS — sześciocyfrowy kod na numer z profilu, hasło ustawia się na miejscu,
- Link e-mail — mail „Prośba o zmianę hasła" z linkiem ważnym 24 godziny.
Jeśli maila nie udało się wysłać, klient dostaje czerwony komunikat zamiast ekranu „Sprawdź skrzynkę".
Link wygasł
Po 24 godzinach link prowadzi na ekran z informacją o nieaktualnym linku. Klient wraca na ekran logowania i wpisuje adres e-mail jeszcze raz — nowy mail wychodzi automatycznie.
Zmiana hasła z własnego profilu
Zalogowany klient zmienia hasło w Profil → Dane osobowe → Bezpieczeństwo. Sekcja pojawia się tylko wtedy, gdy konto ma własne hasło — konto założone wyłącznie przez Google lub Apple najpierw ustawia hasło linkiem z maila.
Formularz prosi o obecne hasło oraz dwukrotnie o nowe. Po zapisaniu klient zostaje zalogowany na bieżącym urządzeniu, a wszystkie pozostałe sesje są wylogowywane. Błędne obecne hasło zatrzymuje zapis i podświetla pole zamiast pokazywać potwierdzenie.
🛠️ Dokumentacja techniczna
Przepływ
Dlaczego requestResetMail
Better Auth odpowiada na /request-password-reset zawsze status: true —
nieznany adres i awaria SendGrida wyglądają identycznie jak sukces (callback
sendResetPassword jest wołany przez runInBackgroundOrAwait, który łyka
wyjątek do logu). Dlatego callback zapisuje faktyczny wynik przez
recordResetMailDelivery, a lib/auth-reset-mail.ts odczytuje go zaraz po
wywołaniu i zwraca:
reason | Znaczenie |
|---|---|
sent | SendGrid przyjął wiadomość |
no_account | Better Auth nie znalazł konta — nic nie poszło |
send_failed | Wysyłka rzuciła wyjątkiem |
Bez tego każdy ekran mówił „wysłaliśmy maila" niezależnie od tego, czy cokolwiek wyszło.
Wybór szablonu
sendResetPassword (lib/auth.ts) rozpoznaje zaproszenie po redirectTo
kończącym się na /auth/set-password albo po nagłówku x-is-invitation: true.
Zaproszenie → mails/auth-invitation.html, reset → mails/auth-reset-password.html.
Oba szablony zawierają przycisk oraz ten sam adres jako widoczny link.
Treść zaproszenia jest celowo neutralna („ustaw swoje hasło"), bo ten sam mail trafia zarówno do świeżo założonych kont, jak i do kont, które istnieją od dawna, a nigdy nie miały własnego hasła.
Ważność linku
resetPasswordTokenExpiresIn w lib/auth.ts to 24 godziny (domyślne
Better Auth to 1 godzina — za mało dla zaproszenia, które klient otwiera przy
najbliższym zaglądnięciu do skrzynki). Wartość obowiązuje oba szablony, więc
zmiana wymaga poprawienia zdania o ważności w obu plikach mails/.
Punkty wejścia
| Miejsce | Funkcja |
|---|---|
lib/actions/users.ts → inviteUser | zaproszenie po createUser |
lib/set-password-invite.ts | konto bez hasła (login, trial) |
lib/actions/users.ts → resetPassword | kanał e-mail w /auth/recover |
resendSetPasswordInvitation wysyła wyłącznie do kont bez konta
credential — konto z hasłem musi przejść zwykłą ścieżką odzyskiwania, więc
endpointu nie da się użyć do zasypywania maili istniejącym użytkownikom.
Zmiana hasła z profilu
components/forms/userProfile/userPasswordForm.tsx woła
authClient.changePassword({ currentPassword, newPassword, revokeOtherSessions: true }),
czyli endpoint POST /api/auth/change-password. Hasło żyje w tabeli account
(providerId = 'credential'), której updateUser ani updateUserInDb nie
dotykają — formularz wysyłał wcześniej password w zwykłej aktualizacji
profilu, więc pole było po cichu pomijane, a toast i tak mówił o sukcesie.
Widoczność sekcji steruje showPasswordSection w userProfileModern.tsx,
wyliczone z hasPassword (lib/actions/users-db.ts → providery konta).
Błąd INVALID_PASSWORD z Better Auth oznacza złe obecne hasło i jest mapowany
na komunikat przy polu; każdy inny błąd kończy się ogólnym komunikatem, bez
czyszczenia formularza.