Skip to main content

Automatyczne wpisywanie kodu z SMS

Kod weryfikacyjny wysyłany SMS-em (logowanie numerem telefonu, rezerwacja bez konta, zapis na zajęcia próbne, potwierdzanie numeru w profilu) może zostać wpisany przez telefon jednym dotknięciem, zamiast przepisywania sześciu cyfr z powiadomienia.

👤 Instrukcja dla klienta

iPhone

Po otrzymaniu SMS-a nad klawiaturą pojawia się podpowiedź z kodem — wystarczy ją dotknąć. Podpowiedź działa zarówno w Safari, jak i w aplikacji AcePark.

Android

Chrome pokazuje okienko „Czy chcesz wypełnić kod?”. Po potwierdzeniu pole wypełnia się samo i weryfikacja rusza dalej bez dodatkowego kliknięcia.

Kiedy podpowiedź się nie pojawi

  • Gdy kod jest przepisywany na innym urządzeniu niż to, które dostało SMS-a.
  • Gdy strona jest otwarta w przeglądarce innej niż Safari (iOS) lub Chrome (Android).
  • Gdy kalendarz rezerwacji jest osadzony jako ramka na stronie zewnętrznej — podpowiedź obejmuje wtedy tylko domenę samej ramki.

🔧 Dokumentacja techniczna

Treść SMS-a

sendVerificationSms w lib/sms.ts buduje wiadomość w formacie, którego szukają obie platformy — ostatnia linia to @domena #kod:

Twój kod weryfikacyjny to: 034992

@klient.acepark.pl #034992

Domena musi być dokładnie tym hostem, na którym klient wpisuje kod. Nie ma dopasowania po masce ani dziedziczenia z domeny nadrzędnej: @acepark.pl nie zadziała na klient.acepark.pl. Co ważniejsze, sam ten format wyłącza heurystyczne wykrywanie kodu w iOS — niepasująca domena jest gorsza niż brak tej linii, bo nie zostaje żaden mechanizm zapasowy.

Dlatego domena czytana jest z nagłówka host bieżącego żądania, a nie ze zmiennej BETTER_AUTH_URL, która potrafi wskazywać inny host niż ten otwarty w przeglądarce (w środowisku dev różniły się: klientdev.acepark.pl vs dev.klient.acepark.pl). Poza kontekstem żądania — np. w cronie — helper wraca do wartości ze zmiennej środowiskowej.

iOS: powiązanie aplikacji z domeną

W WebView aplikacji (Capacitor) podpowiedź wymaga zweryfikowanego powiązania domeny z aplikacją:

  • ios/App/App/App.entitlements deklaruje webcredentials: dla domeny klienta i dla domen deweloperskich,
  • app/.well-known/apple-app-site-association/route.ts serwuje plik powiązania z nagłówkiem application/json,
  • middleware przepuszcza cały prefiks /.well-known/ bez sesji — Apple pobiera ten plik anonimowo i nie podąża za przekierowaniem, więc odesłanie na ekran logowania po cichu psuje całe powiązanie.

Sekcja applinks.details jest celowo pusta: universal links nigdy nie były na tej domenie aktywne, a ich włączenie zaczęłoby przechwytywać wszystkie linki do aplikacji.

Po zmianie domen w entitlements potrzebny jest nowy build aplikacji — iOS pobiera plik powiązania przy instalacji, nie przy każdym uruchomieniu.

Android: Web OTP API

Chrome nie reaguje na sam atrybut autocomplete="one-time-code" — strona musi sama poprosić o kod. Robi to hook hooks/useWebOtpAutofill.ts, wpięty w współdzielony komponent components/ui/input-otp.tsx, więc obejmuje wszystkie ekrany z kodem bez zmian w każdym z osobna.

Hook pyta o kod tylko wtedy, gdy przeglądarka wspiera OTPCredential i strona jest w bezpiecznym kontekście, a przy odmontowaniu pola przerywa żądanie przez AbortController. Aplikacja Android to TWA renderowane przez Chrome, więc działa tam ten sam mechanizm co w przeglądarce.

Testy

PlikCo pokrywa
__tests__/lib/sms.test.tsdomena z hosta żądania, obcięcie portu, fallback poza żądaniem, pozycja linii
__tests__/middleware.well-known.test.tsbrak przekierowania /.well-known/ na logowanie
__tests__/components/input-otp-web-otp.test.tsxwywołanie Web OTP, przycięcie kodu do długości pola, brak wywołania bez wsparcia