To są tematy, w których frontend i backend bardzo mocno na siebie wpływają. Wybór między SSE a WebSocketami zmienia sposób budowania . Źle obsłużony webhook potrafi podwoić zamówienie. Integracja bez ponowień i limitów zaczyna losowo psuć checkout. Niejasny model uwierzytelniania kończy się losowymi 401, problemami z cookie i debugowaniem, które wygląda jak szukanie błędu po omacku.
1. Real-time w backendzie: WebSocket, SSE i polling w aplikacji webowej
REST dobrze obsługuje klasyczny model „zapytaj i dostań odpowiedź”. Nie wystarcza jednak wtedy, gdy serwer ma sam poinformować użytkownika o zmianie: nowej wiadomości, statusie zadania, postępie generowania odpowiedzi AI albo aktualizacji dashboardu. Wtedy wchodzą , SSE i WebSockets.
Polling jako najprostsze rozwiązanie real-time
Polling jest najprostszy mentalnie: frontend pyta co kilka sekund, czy coś się zmieniło. Nie wymaga specjalnej infrastruktury, ale płacisz za to opóźnieniem i dodatkowymi żądaniami.
W przypadku long pollingu żądanie pozostaje otwarte, dopóki backend nie ma czego zwrócić.
Long polling działa prawie wszędzie i bywa dobrym rozwiązaniem awaryjnym, ale w nowych projektach zwykle warto najpierw rozważyć SSE albo WebSockets.
Server-Sent Events (SSE) do komunikacji serwer klient
SSE to jednokierunkowy strumień serwer → klient. Działa na zwykłym HTTP i ma automatyczne wznawianie połączenia, więc świetnie pasuje do sytuacji, w których klient nie musi odsyłać wiadomości tym samym kanałem.
Idealne dla: powiadomień, feedów, strumieniowania AI i pokazywania postępu na żywo.
Na co uważać: przy HTTP/1.x przeglądarki mają niski limit równoległych połączeń do jednej domeny, więc wiele otwartych kart z SSE może zablokować kolejne strumienie. Przy HTTP/2 limit jest negocjowany jako liczba strumieni, ale nadal zależy od konfiguracji klienta, serwera i proxy. Proxy nie może buforować odpowiedzi, a serwer powinien okresowo wysyłać komentarz lub zdarzenie, aby połączenie nie wygasło.
Natywny EventSource nie pozwala ustawić własnego nagłówka Authorization. Dla aplikacji webowej najprostsze jest zwykle uwierzytelnienie przez bezpieczne cookie tego samego originu. Token w adresie URL powinien być krótkotrwały, jednorazowy i używany tylko wtedy, gdy nie da się zastosować cookie, ponieważ adres może trafić do logów, historii i narzędzi monitorujących. Jeżeli klient ma odzyskiwać pominięte dane po ponownym połączeniu, backend musi zapisywać identyfikatory zdarzeń i obsłużyć nagłówek Last-Event-ID. Samo automatyczne ponowne połączenie nie gwarantuje odtworzenia wiadomości.
WebSockets w aplikacji webowej
WebSocket tworzy dwukierunkowy, trwały kanał. To już nie jest zwykłe żądanie i odpowiedź, tylko osobny protokół (ws:// / wss://) z uzgodnieniem połączenia opartym na HTTP Upgrade.
Idealne dla: chatów, gier, współpracy w czasie rzeczywistym (Figma, Notion, Google Docs) i notowań na żywo.
WebSocket, SSE czy polling: co wybrać?
Jeżeli potrzebujesz tylko wysyłać aktualizacje z serwera do klienta, SSE jest prostsze. Jeżeli klient i serwer mają rozmawiać w obie strony w czasie rzeczywistym, wybierz WebSockets.
| Scenariusz | Rozwiązanie |
|---|---|
| Powiadomienia "nowy komentarz" | SSE |
| Chat 1-on-1 / pokoje | WebSockets |
| Strumieniowanie AI | SSE |
| Gra w czasie rzeczywistym | WebSockets |
| Status zadania w tle | SSE / polling |
| Kolaboracja na dokumencie (CRDT) | WebSockets |
Popularne biblioteki i usługi: Socket.IO, Pusher, Ably, Soketi i Cloudflare Durable Objects. Socket.IO korzysta z własnego protokołu opartego na Engine.IO, może zacząć od HTTP long pollingu i przejść na WebSocket. Nie jest więc bezpośrednio zgodne z surowym klientem WebSocket.
Wyzwania real-time: skalowanie, ponowne połączenie i autoryzacja
- Skalowanie horyzontalne wymaga wspólnej dystrybucji zdarzeń. Redis pub/sub lub NATS pasują do szybkiego fan-outu. Kafka lepiej sprawdza się jako trwały dziennik zdarzeń, gdy liczy się odtwarzanie i wielu niezależnych konsumentów.
- Autoryzację trzeba sprawdzać dla każdego kanału i komunikatu. Samo uwierzytelnienie podczas handshake nie daje prawa do wejścia do dowolnego pokoju ani wykonania każdej operacji.
- Sticky sessions zależą od transportu i architektury. Są często potrzebne przy rozwiązaniu awaryjnym opartym na long pollingu lub stanie trzymanym lokalnie. Po zestawieniu zwykłego WebSocketu połączenie i tak pozostaje przy jednej instancji.
- Ponowne połączenie wymaga strategii wznawiania danych. W SSE pomaga
Last-Event-ID, ale backend nadal musi przechowywać zdarzenia i umieć zwrócić brakujący zakres. - Heartbeat i limit czasu wykrywają martwe połączenia. Sam status „open” nie dowodzi, że klient nadal ma łączność.
- Backpressure i limity chronią pamięć serwera. Ogranicz rozmiar wiadomości, liczbę połączeń i tempo komunikatów.
- Origin, schemat wiadomości i uprawnienia wymagają walidacji. WebSocket omija część typowego cyklu middleware HTTP, dlatego każdą wiadomość trzeba traktować jak niezaufane dane wejściowe.
- Proxy i mają własne limity. Przed wyborem transportu sprawdź czas trwania połączeń i zachowanie , load balancera oraz platformy hostingowej.
2. Webhooki w backendzie: bezpieczna obsługa zdarzeń z zewnętrznych systemów
to odwrócone wywołanie API. Zamiast co minutę pytać system płatności „czy faktura jest już opłacona?”, pozwalasz mu samemu poinformować Twoją aplikację, gdy coś się wydarzy. To prosty wzorzec, ale wymaga dyscypliny: podpisy, ponowienia, idempotencja i szybka odpowiedź są tutaj krytyczne.
Trzy zasady bezpiecznych webhooków
1. Weryfikuj podpis
Dostawca podpisuje treść żądania (najczęściej HMAC-SHA256 z sekretem). Bez weryfikacji ktoś może udawać Stripe i oznaczać zamówienia jako opłacone:
2. Odpowiadaj szybko
Webhook to nie miejsce na ciężką logikę. Dostawca zwykle oczekuje szybkiej odpowiedzi 2xx. Przekroczenie limitu czasu albo inny status może spowodować ponowienie. Potwierdź odbiór dopiero po trwałym zapisaniu zdarzenia, a logikę biznesową wykonaj asynchronicznie.
3. Idempotency chroni przed duplikatami
Ten sam webhook może przyjść kilka razy. Dodaj unikalny indeks złożony, na przykład dla provider i eventId. Samo sprawdzenie findUnique, a potem osobny create, ma wyścig między równoległymi żądaniami. O idempotencji powinno rozstrzygać ograniczenie w bazie.
Nie oznaczaj zdarzenia jako przetworzonego przed wykonaniem logiki biznesowej. Worker powinien zmienić status z pending na processing, zapisać processed dopiero po sukcesie i pozostawić błąd oraz licznik prób po niepowodzeniu. Dzięki temu ponowienie pracy nie zgubi płatności.
Bezpieczny przepływ webhooka krok po kroku
Najbezpieczniejszy schemat wygląda tak:
- Odbierz
raw body, zanim parser JSON zmieni treść żądania. - Zweryfikuj podpis i świeżość timestampu.
- Zapisz
event.id, typ, treść żądania i statuspendingw bazie. - W tej samej transakcji dodaj rekord outbox, który niezawodnie zasili kolejkę.
- Jeśli
event.idjuż istnieje, nie twórz drugiego zadania. - Odpowiedz szybko
2xx, ale dopiero po zatwierdzeniu transakcji. - Worker przetwarza zdarzenie i atomowo zapisuje wynik operacji biznesowej.
- Osobny proces ponawia rekordy
pendingi błędy przejściowe.
To rozdziela dwa problemy: dostarczenie zdarzenia i przetworzenie zdarzenia. Dzięki temu ponowienie dostawcy nie tworzy duplikatów, a awaria Twojej logiki biznesowej nie musi oznaczać utraty informacji o płatności.
Lokalne testowanie webhooków przez tunel publiczny
Webhook nie dojdzie bezpośrednio na localhost:3000, bo zewnętrzny system musi mieć publiczny adres, pod który może wysłać żądanie. Do pracy lokalnej używa się tuneli:
- ngrok daje publiczny URL. Uruchom
ngrok http 3000. - Stripe CLI przekazuje zdarzenia na localhost. Użyj
stripe listen --forward-to localhost:3000/webhooks/stripe. - Cloudflare Tunnel jest alternatywą dla ngrok.
- smee.io przekazuje webhooki z GitHuba.
Popularne źródła webhooków: Stripe, GitHub, CMS i CRM
- Stripe obsługuje zdarzenia płatności, na przykład
payment_intent.succeedediinvoice.paid. - GitHub wysyła zdarzenia repozytorium, między innymi
push,pull_requestiissues. - Resend i SendGrid raportują dostarczenie wiadomości, odbicia oraz skargi.
- Slack obsługuje komendy i zdarzenia aplikacji.
- Twilio raportuje statusy SMS-ów i połączeń.
- Clerk i Auth0 informują o cyklu życia użytkownika.
- Vercel wysyła zdarzenia dotyczące wdrożeń.
3. Integracje API z zewnętrznymi usługami
Webhooki są integracją przychodzącą. Druga połowa tematu to integracje wychodzące: Twoja aplikacja woła Stripe, Slacka, OpenAI, system ERP, bramkę SMS albo CRM. Dla frontendu często wygląda to jak jeden przycisk „Wyślij”, ale po stronie backendu trzeba obsłużyć wolne odpowiedzi, limity, ponowienia i częściowe awarie.
Najważniejsza zasada: zewnętrzne API nie jest częścią Twojej aplikacji. Może zwolnić, zwrócić 429, zmienić komunikat błędu, mieć przerwę techniczną albo odpowiedzieć po czasie, gdy użytkownik już zamknął ekran.
Kontrakt integracji API: limity czasu, ponowienia i rate limit
Każda poważniejsza integracja powinna mieć:
Jawny limit czasu żądania. Połączenie nie może wisieć w nieskończoność.
Ponawiaj tylko błędy przejściowe. Stosuj exponential backoff z jitterem dla błędów sieciowych,
408,429i wybranych5xx.Obsługę limitów dostawcy. Respektuj
Retry-After, limity konta i limity konkretnego endpointu.Klucz idempotencji dla mutacji. Jest szczególnie ważny przy płatnościach, zamówieniach i tworzeniu zasobów.
Mapowanie błędów na własny kontrakt. Nie pokazuj użytkownikowi surowej odpowiedzi dostawcy.
Logowanie identyfikatora żądania dostawcy. Ułatwia wsparcie i debugowanie.
Kolejkę dla wolnych operacji. Użyj jej, gdy zadanie jest drogie albo nie musi zakończyć się w tym samym żądaniu.
Przykład ponawiania dla bezpiecznego żądania GET:
Nie ponawiaj automatycznie POST, PATCH ani innych operacji zmieniających stan, jeżeli API nie zapewnia idempotencji. Timeout nie mówi, czy dostawca wykonał operację. Odpowiedź mogła zginąć już po utworzeniu płatności lub zamówienia.
Kolejka zadań zamiast synchronicznej odpowiedzi w integracjach
Jeżeli użytkownik musi natychmiast zobaczyć wynik, backend może poczekać na odpowiedź dostawcy. Jeżeli operacja jest ciężka albo podatna na awarie, lepiej zapisać zadanie i przetworzyć je asynchronicznie.
| Scenariusz | Lepszy wzorzec |
|---|---|
| Sprawdzenie kuponu w checkout | synchroniczna odpowiedź |
| Wysłanie e-maila po rejestracji | kolejka |
| Import 20 000 rekordów z CRM | kolejka + status postępu |
| Wystawienie faktury po płatności | webhook + kolejka |
| Synchronizacja katalogu produktów | cron / zadanie cykliczne + ponowienia |
| Powiadomienie UI o zakończeniu zadania | SSE, WebSocket albo polling |
Dead-letter queue i monitoring nieudanych integracji API
Ponawianie nie może trwać bez końca. Po kilku nieudanych próbach zadanie powinno trafić do dead-letter queue albo statusu failed, który ktoś może przejrzeć i uruchomić ponownie ręcznie. Bez tego integracja „czasem nie działa”, ale nikt nie wie, które rekordy utknęły.
Dla frontendowca ważny jest też model stanu:
queuedoznacza zadanie przyjęte,processingoznacza pracę backendu,succeededoznacza zakończenie operacji,failed_retryableoznacza problem przejściowy i kolejną próbę,failed_finaloznacza potrzebę działania użytkownika lub wsparcia.
To pozwala zbudować UI, który nie udaje, że wszystko dzieje się synchronicznie.
4. Autentykacja i autoryzacja w backendzie
To są dwa różne pojęcia, które często wrzuca się do jednego worka. Autentykacja odpowiada na pytanie „kim jesteś?”, a autoryzacja na pytanie „co możesz zrobić?”. Frontend odczuwa oba mechanizmy przez logowanie, wygasające sesje, ukrywanie elementów UI i błędy 401 / 403, ale prawdziwa decyzja zawsze musi zapaść na backendzie.
| Status | Co oznacza | Reakcja UI |
|---|---|---|
401 | Nie wiadomo, kim jesteś | Spróbuj odświeżyć sesję albo pokaż login |
403 | Wiadomo, kim jesteś, ale nie masz dostępu | Pokaż brak uprawnień, nie przekierowuj na login |
419 / 440 | Kody niestandardowe używane przez część frameworków | Obsłuż tylko wtedy, gdy definiuje je kontrakt API |
429 | Za dużo prób logowania lub żądań | Pokaż cooldown i nie spamuj ponowieniami |
401, 403 i 429 są standardowymi kodami HTTP. 419 oraz 440 to konwencje frameworków i dostawców, dlatego frontend nie powinien zakładać ich znaczenia bez dokumentacji własnego API.
Autentykacja użytkownika: hasło, OIDC, magic link i passkeys
Autentykacja to weryfikacja tożsamości użytkownika.
Metody:
- Hasło jest tradycyjną metodą logowania.
- OpenID Connect obsługuje logowanie przez zewnętrznego dostawcę. Sam deleguje autoryzację do zasobów i nie jest protokołem uwierzytelniania.
- Magic link pozwala zalogować się przez wiadomość e-mail.
- Passkeys używają FIDO2 i WebAuthn. Użytkownik zwykle odblokowuje poświadczenie biometrią, PIN-em albo kluczem sprzętowym.
W logowaniu przez dostawcę używaj Authorization Code Flow z PKCE. Parametry transakcji muszą być unikalne. Waliduj state, a w OpenID Connect także nonce, issuer, audience i podpis ID tokenu. Nie buduj tego mechanizmu ręcznie, gdy biblioteka dostawcy wykonuje pełną walidację protokołu.
Bezpieczne hasła, reset konta i ochrona logowania
Hasła zapisuj jako wolne, solone hashe, nigdy jako tekst jawny ani odwracalne szyfrogramy. OWASP rekomenduje Argon2id dla nowych systemów z minimalnymi parametrami 19 MiB pamięci, 2 iteracji i równoległości 1. scrypt jest alternatywą, gdy Argon2id nie jest dostępny. bcrypt z work factor co najmniej 10 traktuj jako rozwiązanie dla starszych systemów i pamiętaj o limicie 72 bajtów wejścia.
Sam hashing nie zamyka tematu. Endpoint logowania powinien mieć rate limiting, komunikaty nieujawniające, czy konto istnieje, oraz monitoring nietypowych prób. Po logowaniu i każdej zmianie poziomu uprawnień regeneruj identyfikator sesji, aby ograniczyć session fixation. Reset hasła, zmiana adresu e-mail i odzyskiwanie konta wymagają ponownej autentykacji, audytu oraz możliwości unieważnienia aktywnych sesji.
Autoryzacja w API: role, uprawnienia i decyzje backendu
Autoryzacja to sprawdzanie uprawnień. UI może ukryć przycisk „Usuń użytkownika”, ale backend i tak musi sprawdzić rolę przy samym żądaniu.
JWT (JSON Web Token) w API i aplikacji webowej
JWT to format tokenu, a nie magiczny zamiennik sesji. Często sprawdza się w API i integracjach między usługami, ale w klasycznych aplikacjach webowych sesje nadal bywają prostsze operacyjnie. Podpis JWT zapewnia integralność, nie poufność. Treść zwykłego JWS można odczytać, dlatego nie umieszczaj w nim sekretów.
Przykładowy przepływ:
- Użytkownik loguje się → serwer tworzy krótko żyjący token
- Frontend trzyma go bezpiecznie (np. w pamięci) albo korzysta z mechanizmu ciasteczek (cookies)
- Przeglądarka wysyła token w nagłówku lub cookie
- Serwer weryfikuje podpis albo identyfikator sesji przy każdym żądaniu
Sesje serwerowe w Redisie lub bazie danych
W sesjach serwerowych stan jest przechowywany w bazie lub Redisie.
JWT vs sesje: kompromisy architektoniczne
| Cecha | Sesja | JWT |
|---|---|---|
| Stan | Dane sesji są w Redisie lub bazie | Roszczenia są w tokenie |
| Unieważnienie | Zwykle natychmiastowe po usunięciu sesji | Wymaga krótkiego TTL, listy cofnięć lub wersji |
| Skalowanie | Wymaga wspólnego magazynu sesji | Walidacja może działać bez odczytu z bazy |
| Rozmiar żądania | Zwykle mały, losowy identyfikator | Cały token jest wysyłany z każdym żądaniem |
| Stan operacyjny | Jawnie przechowywany po stronie serwera | Często wraca przy rotacji i unieważnianiu |
| Wiele domen | Wymaga poprawnej konfiguracji cookie i CORS | Wymaga bezpiecznego transportu, magazynu i CORS |
Nie wybieraj JWT tylko ze względu na skalowanie. Wspólny magazyn sesji jest prostym i dojrzałym rozwiązaniem, a JWT przestaje być całkowicie bezstanowy, gdy dodasz natychmiastowe wylogowanie, rotację refresh tokenów albo wykrywanie kradzieży.
W klasycznej aplikacji webowej sesja w HttpOnly cookie jest często prostsza niż własny system JWT. JWT ma sens, gdy odbiorcy muszą lokalnie weryfikować podpisany token lub gdy architektura ma jasno zdefiniowane issuer, audience, krótki TTL i mechanizm cofania dostępu.
Cookies w autentykacji: HttpOnly, Secure i SameSite
Cookies wyglądają niepozornie, ale przy autentykacji każdy flag ma znaczenie. Jedna błędna konfiguracja potrafi zrobić różnicę między rozsądnym modelem bezpieczeństwa a tokenem, który wycieka przez XSS albo jest wysyłany w niepożądanym kontekście.
| Flaga | Co robi | Ważne ograniczenie |
|---|---|---|
| HttpOnly | Blokuje dostęp przez document.cookie | XSS nadal może wysyłać żądania w imieniu użytkownika |
| Secure | Wysyła cookie wyłącznie po HTTPS | Nie zastępuje HttpOnly ani ochrony przed XSS |
| SameSite=Strict | Blokuje cookie w żądaniach cross-site | Może utrudnić wejście do aplikacji z zewnętrznego linku |
| SameSite=Lax | Dopuszcza część nawigacji top-level z bezpieczną metodą | To ochrona warstwowa, nie pełny zamiennik tokenu CSRF |
| SameSite=None | Pozwala wysyłać cookie cross-site i wymaga Secure | Potrzebne między innymi w części scenariuszy osadzania |
| Path | Ogranicza adresy, do których przeglądarka wysyła cookie | Nie jest granicą bezpieczeństwa |
| Domain | Rozszerza wysyłanie cookie na wskazaną domenę i subdomeny | Pomijaj, jeśli subdomeny nie muszą dostawać cookie |
__Host- | Wymaga Secure, Path=/ i braku Domain | Utrudnia nadpisanie cookie przez inną subdomenę lub ścieżkę |
| Max-Age / Expires | Określa czas przechowywania cookie | Sesja i tak musi wygasać oraz być unieważniana po stronie API |
Nie zakładaj, że brak SameSite zawsze oznacza identyczne zachowanie. Część przeglądarek stosuje wtedy wariant Lax, który przez krótki czas może dopuścić także niektóre żądania POST. Ustaw wartość jawnie.
CSRF w aplikacjach webowych z cookies
Jeśli używasz cookies do uwierzytelniania, musisz rozumieć (Cross-Site Request Forgery). Atakujący nie musi znać tokena użytkownika. Wystarczy, że użytkownik jest zalogowany, a przeglądarka automatycznie dołączy cookie do żądania wysłanego z obcej strony.
Przeglądarka sama dołączy cookie uwierzytelniające do tego POST-a, jeśli SameSite na to pozwala.
Obrona powinna składać się z kilku warstw:
- Ustaw
SameSite=LaxlubStrictna cookie uwierzytelniającym. Traktuj to jako ochronę dodatkową, ponieważ pojęcie same-site obejmuje także inne subdomeny tej samej domeny rejestrowalnej. - Stosuj token synchronizer dla sesji stanowych. Backend zapisuje sekret w sesji i porównuje go z wartością przesłaną jawnie przez frontend.
- Dla rozwiązania bezstanowego użyj podpisanego double-submit cookie. Token musi być związany z konkretną sesją. Naiwne porównanie dwóch wartości cookie jest podatne na cookie injection.
- Sprawdzaj
OriginlubRefererdla operacji zmieniających stan. W nowoczesnych przeglądarkach możesz dodatkowo wykorzystać nagłówki Fetch Metadata, na przykładSec-Fetch-Site. - Nie zmieniaj stanu przez
GET. Metody uznawane za bezpieczne nie powinny wykonywać przelewów, usuwać danych ani zmieniać ustawień.
Token trzymany w localStorage i ręcznie dodawany do nagłówka nie jest automatycznie wysyłany przez przeglądarkę, co ogranicza klasyczny CSRF. Nadal może zostać odczytany przez . Cookie HttpOnly ogranicza bezpośrednią kradzież tokena przez JavaScript, ale XSS wciąż może wysyłać uwierzytelnione żądania z poziomu aplikacji.
Nie ma jednego „najlepszego” miejsca na token dla każdej aplikacji. Dla klasycznej aplikacji webowej najczęściej wygrywa cookie HttpOnly + Secure + SameSite=Lax/Strict. Dla korzystającej z OAuth coraz częściej spotkasz wariant: krótko żyjący access token w pamięci aplikacji i refresh token w bezpiecznym, HttpOnly cookie albo obsługę uwierzytelniania przez BFF.
Refresh token rotation i wykrywanie kradzieży tokena
Access token powinien mieć krótki czas życia, a refresh token może działać dłużej. Konkretne wartości zależą od ryzyka aplikacji. Poniższe 15 minut i 7 dni są tylko przykładem.
Skuteczna rotacja musi przechowywać relację między tokenami. Jeżeli ktoś ponownie użyje starego refresh tokena, serwer wykrywa ponowne użycie i unieważnia aktywną rodzinę tokenów powiązaną z tym grantem. Nie musi to oznaczać wylogowania ze wszystkich urządzeń użytkownika. Zakres unieważnienia zależy od modelu sesji i implementacji. Dla klientów publicznych OAuth Security BCP wymaga refresh tokenów związanych z nadawcą albo rotacji wykrywającej ponowne użycie.
Z perspektywy frontendu są tu trzy ważne reguły:
- Nie rób nieskończonej pętli odświeżania. Jeśli refresh zwróci
401, wyczyść stan i pokaż login. - Zablokuj równoległe odświeżenia. Gdy pięć żądań naraz dostanie
401, tylko jedno powinno odświeżać token, a reszta poczekać na wynik. - Rozróżniaj brak uwierzytelnienia od braku uprawnień.
401może uruchomić refresh, ale403powinien pokazać brak dostępu.
MFA, TOTP, WebAuthn i passkeys jako drugi czynnik logowania
Hasło to wiedza, czyli coś, co użytkownik zna. MFA dodaje coś, co użytkownik ma, albo cechę, którą potwierdza lokalnie.
- TOTP generuje krótkie kody czasowe. Korzystają z niego między innymi aplikacje uwierzytelniające zgodne z RFC 6238.
- WebAuthn i passkeys używają kryptografii klucza publicznego. Poświadczenie może znajdować się w kluczu sprzętowym lub uwierzytelniaczu platformowym.
- SMS jest wygodny, ale słabszy. Jest podatny między innymi na SIM swap i phishing.
- Powiadomienia push wymagają ochrony przed zmęczeniem MFA. Sam przycisk zatwierdzenia bez kontekstu może prowadzić do przypadkowej akceptacji.
Passkeys są odporne na typowy phishing, ponieważ poświadczenie jest związane z domeną. Serwer przechowuje klucz publiczny, a klucz prywatny pozostaje na urządzeniu albo w zaufanym menedżerze poświadczeń. Biometria odblokowuje uwierzytelniacz lokalnie i nie jest wysyłana do serwera. W praktyce trzeba przewidzieć kody odzyskiwania, rejestrację drugiego urządzenia, bezpieczne usuwanie poświadczeń oraz procedurę odzyskania konta.
Gotowe rozwiązania do auth: Auth.js, Clerk, Supabase Auth, Auth0 i Okta
Autoryzacja i uwierzytelnianie to obszary, w których samodzielne pisanie kodu od zera rzadko kończy się dobrze, dlatego w środowisku produkcyjnym zawsze warto stawiać na sprawdzone narzędzia lub przynajmniej dojrzałe, przetestowane biblioteki.
jest otwartym rozwiązaniem popularnym w Next.js.
Clerk dostarcza zarządzany auth i gotowe interfejsy. Koszt zależy od skali i używanych funkcji.
Supabase Auth integruje się z pozostałymi usługami Supabase.
Auth0 i Okta oferują rozbudowane funkcje dla organizacji.
Lucia jest obecnie zasobem edukacyjnym do implementowania sesji, a nie biblioteką zalecaną do nowych wdrożeń.
jest rozwiązaniem niezależnym od jednego frameworka.
