Dyskusja „JWT kontra sesja” bywa przedstawiana jako wybór między nowoczesnością a przeszłością. Oba modele rozwiązują podobny problem, lecz inaczej rozmieszczają stan. Sesja przechowuje aktualne dane na serwerze i daje klientowi losowy identyfikator. JWT przenosi podpisane claims i pozwala zweryfikować je lokalnie. Żaden wariant nie jest automatycznie bezpieczniejszy ani bardziej skalowalny.

Sesja utrzymuje prawdę po stronie serwera

Po logowaniu backend generuje losowe session ID i zapisuje użytkownika, expiry oraz stan w bazie lub cache. Przeglądarka wysyła ID zwykle w HttpOnly cookie. Każdy request odczytuje bieżący rekord.

Logout, blokada konta i zmiana uprawnień mogą działać natychmiast przez aktualizację lub usunięcie sesji. Store musi być za to szybki i wysoko dostępny.

JWT przenosi snapshot stanu do klienta

API może sprawdzić podpis i claims bez połączenia z issuerem przy każdym request. To przydatne między niezależnymi usługami lub w federacji. Informacje pozostają jednak niezmienne do expiry.

Refresh tokens, urządzenia, revocation i klucze nadal tworzą stan serwerowy. JWT może ograniczyć częsty lookup, ale nie usuwa wszystkich baz danych.

Klasyczna aplikacja webowa często zyskuje na sesji

Gdy browser i backend należą do jednego produktu, bezpieczne session cookie jest prostym, dobrze znanym modelem. Token nie musi być czytelny dla JavaScript, logout jest bezpośredni, a role można sprawdzać na bieżąco.

Skalowanie poziome działa z wspólnym Redis lub bazą. Centralny store jest zwykle stabilniejszy niż przywiązanie użytkownika do jednego hosta.

Wiele API może skorzystać z krótkiego access tokena

Identity Provider wystawia token dla konkretnej audience, a każda usługa sprawdza go public key. Private key nie jest kopiowany do całej infrastruktury. Serwisy zachowują niezależność od centralnego lookup podczas requestu.

Wymaga to spójnej semantyki claims, bibliotek i rotacji. Wspólny issuer nie oznacza, że każdy serwis akceptuje każdą audience.

Mobile i zewnętrzni klienci mają inne potrzeby

Native app może przechowywać token w systemowym secure storage i korzystać z OAuth. Publiczny integrator nie powinien otrzymywać cookie przeznaczonego dla strony. Standard delegacji jest ważniejszy niż sam format JWT.

OAuth nie wymaga czytelnego JWT jako access tokena. Opaque token z introspection daje centralną kontrolę i mniejszą ekspozycję danych.

Revocation jest wymaganiem produktu

Administrator może potrzebować natychmiast odciąć użytkownika. Sesję łatwo usunąć. Samodzielnie weryfikowany JWT działa do expiry, jeśli usługa nie sprawdza denylisty lub wersji sesji.

Najpierw należy ustalić maksymalny dopuszczalny czas reakcji. System bankowy i krótkie read-only API mają inne potrzeby.

Cookie i JWT nie są przeciwnymi pojęciami

JWT może znajdować się w cookie, a opaque session ID w Authorization header. Cookie kontra header opisuje transport. JWT kontra losowy identyfikator opisuje zawartość. Pomieszanie tych osi prowadzi do złych ogólnych rad.

Cookie potrzebuje Secure, HttpOnly, SameSite i właściwych granic. Token zarządzany przez JavaScript jest podatny na eksport przy XSS.

Rozmiar tokena kosztuje przy każdym request

Session ID jest krótki. JWT z claims i podpisem może mieć kilka kilobajtów i podróżuje wielokrotnie. Cookies mają dodatkowo limity przeglądarek i proxy.

Token nie powinien być kopią profilu. Należy umieścić tylko dane potrzebne do bezpośredniej decyzji odbiorcy.

Lista aktywnych urządzeń naturalnie pasuje do sesji

Produkt może pokazywać urządzenia, ostatnią aktywność i przycisk zakończenia konkretnej sesji. Rekord serwerowy odwzorowuje ten model bezpośrednio. W architekturze JWT zwykle i tak powstaje rekord refresh session.

To nie jest wada tokenów, tylko dowód, że wymagania użytkownika tworzą trwały stan niezależnie od formatu access credential.

Zachowanie podczas awarii jest inne

Awaria session store może zablokować uwierzytelnienie. Lokalnie weryfikowane JWT mogą działać podczas niedostępności providera aż do expiry. Zwiększa to dostępność, ale opóźnia informację o blokadzie.

Cache kluczy, synchronizacja zegara i wygasanie stają się nowymi zależnościami operacyjnymi. Nie ma architektury bez kosztu.

Model hybrydowy bywa najbardziej pragmatyczny

Browser posiada sesję z Backend-for-Frontend, a BFF przechowuje OAuth tokens i wywołuje wewnętrzne API. Frontend nie otrzymuje eksportowalnych credentials, a usługi nadal używają standardowych tokenów.

Opaque access token z introspection jest innym kompromisem. Jeden produkt nie musi stosować jednego formatu na każdej granicy.

Introspection wymienia lokalną niezależność na aktualność

Przy opaque tokenie API pyta authorization server lub korzysta z krótkiego cache, czy credential jest aktywny i jaki ma scope. Ułatwia to centralne unieważnienie i ukrywa claims przed klientem, ale dodaje zależność sieciową oraz koszt dostępności.

Cache introspection powinien być krótszy niż wymagany czas reakcji na revocation. W przeciwnym razie centralna kontrola istnieje tylko teoretycznie.

Granice między usługami nie zawsze wymagają tokena użytkownika

Przekazywanie tego samego JWT przez cały łańcuch rozszerza jego audience i skutki wycieku. Usługa może zamiast tego wymienić credential na token przeznaczony dla kolejnego odbiorcy albo użyć własnej workload identity.

Delegacja powinna zachować informacje potrzebne do audytu, ale nie dawać każdemu downstream pełnych praw pierwotnego klienta. Najmniejszy scope i konkretna audience ograniczają blast radius.

Wybór powinien wynikać z mierzalnych potrzeb

Sesje pasują do powiązanej aplikacji webowej, natychmiastowego logoutu i często zmienianego stanu. JWT pasuje do jasnych granic usług, wielu niezależnych verifierów i krótkich claims dla konkretnej audience.

Decyzja musi dokumentować storage, transport, CSRF, XSS, expiry, rotację, logout, granice zaufania i zachowanie podczas awarii. Dopiero te właściwości tworzą bezpieczny model uwierzytelniania.