JSON Web Token jest często przedstawiany jako nowoczesny zamiennik sesji. W rzeczywistości to kompaktowy format przenoszenia claims, czyli stwierdzeń o podmiocie lub zdarzeniu, które można zabezpieczyć kryptograficznym podpisem. Sam JWT nie definiuje logowania, logoutu, przechowywania w przeglądarce ani aktualnych uprawnień. Te właściwości powstają dopiero w protokole i architekturze otaczającej token.
Najczęstsza postać ma trzy segmenty
Podpisany JWT, technicznie JWS, zawiera header, payload i signature oddzielone kropkami. Header oraz payload są dokumentami JSON zapisanymi w Base64URL. Podpis obejmuje dokładny tekst dwóch pierwszych segmentów połączonych kropką.
Base64URL jest odwracalne. Każdy posiadacz tokena może odczytać header i claims bez klucza. Poufne dane nie powinny trafiać do zwykłego JWT tylko dlatego, że znajduje się w nim podpis.
Header opisuje sposób weryfikacji
Pole alg wskazuje algorytm, a kid może wybrać klucz z kontrolowanego zestawu. Aplikacja nie może jednak pozwolić tokenowi samodzielnie ustalić polityki bezpieczeństwa. Weryfikator zna wcześniej dozwolone algorytmy dla konkretnego issuera.
Key ID jest niezaufanym wejściem. Powinien wykonywać dokładny lookup w mapie, a nie tworzyć ścieżkę pliku, zapytanie SQL lub dowolny request sieciowy.
Payload zawiera claims, a nie dowody sam w sobie
Standardowe pola obejmują issuer iss, audience aud, subject sub, expiration exp i not-before nbf. Aplikacja może dodać tenant, scope lub role. Każde pole potrzebuje opisanej semantyki.
Poprawny JSON i poprawny podpis nie wystarczają. Token dla innej usługi, innego środowiska albo po terminie musi zostać odrzucony.
Podpis wiąże bytes z posiadaczem klucza
HMAC używa wspólnego sekretu. Każda usługa zdolna zweryfikować token potrafi też stworzyć nowy. Algorytmy asymetryczne rozdzielają role: issuer ma private key, a API otrzymuje tylko public key.
Podpis dowodzi, że chronione bytes pochodzą od strony z odpowiednim kluczem i nie zostały zmienione. Nie dowodzi, że konto jest nadal aktywne lub że akcja jest autoryzowana dla konkretnego obiektu.
Liczy się dokładna serializacja
Dwa obiekty JSON z tymi samymi polami mogą mieć inną kolejność i whitespace. Po kodowaniu dają inny signing input. Weryfikator nie powinien dekodować, formatować i ponownie kodować segmentów przed sprawdzeniem podpisu.
Utrzymywana biblioteka obsługuje Base64URL i format podpisu. Własna implementacja łatwo myli encoding, algorytm albo reprezentację ECDSA.
Czas ogranicza okno użycia
exp określa koniec ważności, nbf najwcześniejszy moment, a iat czas wydania. Niewielki clock skew bywa tolerowany, ale nie powinien zamieniać krótkiego tokena w długowieczny.
Długi access token daje atakującemu dużo czasu po kradzieży. Krótki wymaga odświeżania. Refresh token potrzebuje osobnego, mocniej kontrolowanego lifecycle.
Audience zapobiega użyciu w złej usłudze
Token podpisany przez znanego identity providera może być przeznaczony dla innego API. Sprawdzenie aud ogranicza miejsce, gdzie claims są honorowane. Bez tego token o mniejszym przeznaczeniu może zostać zaakceptowany przez bardziej wrażliwy serwis.
Issuer, audience i typ tokena razem definiują relację zaufania. Sam wspólny klucz publiczny nie oznacza, że każda aplikacja powinna akceptować każdy token.
Rotacja kluczy wymaga okresu nakładania
Nowe tokeny mogą być podpisywane nowym kluczem, podczas gdy stare, jeszcze ważne, potrzebują poprzedniego public key. kid pozwala wybrać właściwy materiał. Usunięcie starego klucza musi uwzględniać maksymalny czas życia.
JWKS jest cache'owany. Nieznany kid może wywołać kontrolowany refresh, lecz nie powinien generować nieograniczonych requestów przy każdym złośliwym tokenie.
JWT nie usuwa całego stanu
API może zweryfikować access token bez bazy. Cały system nadal przechowuje refresh tokens, status konta, consent, sesje urządzeń i klucze. „Stateless” opisuje najwyżej jeden fragment request path.
Natychmiastowy logout lub odebranie roli wymaga krótkiego czasu życia, revocation albo sprawdzenia bieżącego stanu. Wtedy część centralnego lookup wraca i może być właściwym kompromisem.
Transport i storage wpływają na kradzież
Token dostępny dla JavaScript może zostać wykradziony przez XSS. HttpOnly cookie ogranicza odczyt, ale jest wysyłany automatycznie i potrzebuje SameSite oraz ochrony CSRF. Nie istnieje jedna poprawna lokalizacja dla każdego klienta.
Tokenów nie należy umieszczać w URL, ponieważ trafiają do historii, logów i Referer. Mobilny systemowy secure storage ma inne właściwości niż przeglądarka.
Claims starzeją się w czasie życia tokena
Rola zapisana o 10:00 pozostaje w tokenie po odebraniu uprawnienia o 10:05, dopóki nie zadziała expiry lub dodatkowa kontrola. Dynamiczne i krytyczne decyzje powinny korzystać z aktualnego źródła.
Payload warto utrzymywać mały. Profil użytkownika i duże listy praw nie są dobrym substytutem API danych.
Typ tokena musi być jednoznaczny
ID token, access token, refresh token i token resetujący reprezentują inne uprawnienia. Podobny format nie pozwala stosować ich zamiennie. API powinno sprawdzać odpowiedni typ, audience i zestaw claims, zamiast uznawać każdy poprawnie podpisany JWT za credential dostępu.
Oddzielne klucze lub co najmniej odrębna konfiguracja verifiera ograniczają pomyłki. Token przeznaczony dla frontendu nie może zostać przypadkowo użyty do wywołania backendu.
Jti pomaga identyfikować konkretny egzemplarz
Claim jti może nadać tokenowi unikalny identyfikator przydatny w audycie, wykrywaniu replay i selektywnym unieważnieniu. Samo dodanie pola nie tworzy ochrony; odbiorca musi przechowywać lub porównywać stan odpowiedni do celu.
Wartość nie powinna zawierać danych użytkownika. Losowy identyfikator łatwiej bezpiecznie logować i korelować niż cały bearer token.
JWT jest elementem protokołu, nie całym auth
Bezpieczny system definiuje issuer, audience, algorytmy, źródło kluczy, claims, czas życia, storage i reakcję na incydent. Testuje token wygasły, przyszły, źle adresowany i podpisany nieznanym kluczem.
JWT sprawdza się jako interoperacyjna koperta dla podpisanych stwierdzeń. Jego bezpieczeństwo pochodzi z wąskiego kontraktu weryfikacji, a nie z wyglądu trzech segmentów.