Skip to main content

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ę".

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:

reasonZnaczenie
sentSendGrid przyjął wiadomość
no_accountBetter Auth nie znalazł konta — nic nie poszło
send_failedWysył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

MiejsceFunkcja
lib/actions/users.tsinviteUserzaproszenie po createUser
lib/set-password-invite.tskonto bez hasła (login, trial)
lib/actions/users.tsresetPasswordkanał 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.