Logowanie do aplikacji, dostęp do API i komunikacja między usługami często opierają się na krótkim ciągu znaków, który decyduje o tym, kim jesteś i do czego masz dostęp. JWT, czyli JSON Web Token, pozwala przenosić takie informacje między klientem a serwerem, ale jego popularność nie oznacza, że każdy token jest automatycznie bezpieczny. Wyjaśniam, jak działa, z czego się składa, kiedy ma sens oraz jakie błędy mogą narazić aplikację na atak.
JWT przenosi podpisane informacje o użytkowniku
- JWT to kompaktowy token zapisany w formacie JSON Web Signature.
- Składa się z części header, payload i signature.
- Payload można odczytać, dlatego nie wolno umieszczać w nim haseł ani poufnych danych.
- Bezpieczeństwo zależy od weryfikacji podpisu, daty ważności i odbiorcy tokenu.
- Token powinien być przesyłany wyłącznie przez HTTPS i mieć krótki czas życia.

JWT, czyli co to właściwie jest
JSON Web Token to standard opisany w RFC 7519, używany do przekazywania informacji między stronami w postaci niewielkiego, tekstowego tokenu. Najczęściej spotykam go przy uwierzytelnianiu użytkowników, autoryzacji żądań do API oraz komunikacji między mikrousługami.
Po poprawnym zalogowaniu serwer tworzy token i podpisuje go swoim sekretem albo kluczem prywatnym. Klient dołącza go do kolejnych żądań, a serwer sprawdza, czy token jest autentyczny i nadal ważny. Dzięki temu serwer nie musi przechowywać pełnej sesji użytkownika w pamięci.
Najważniejsze rozróżnienie brzmi tak: JWT jest zwykle podpisany, ale nie zaszyfrowany. Podpis chroni przed niezauważoną zmianą danych, natomiast nie ukrywa ich przed osobą, która ma token. Zawartość można łatwo odkodować, choć samo odkodowanie nie oznacza złamania zabezpieczeń.
Do czego wykorzystuje się tokeny
- logowanie do aplikacji internetowej i mobilnej,
- kontrolę dostępu do endpointów API,
- przekazywanie ról lub zakresów uprawnień,
- uwierzytelnianie komunikacji między usługami,
- jednokrotne przekazanie informacji, na przykład w linku aktywacyjnym.
Sam JWT nie jest jednak całym systemem logowania. To tylko format tokenu. O bezpieczeństwie decydują również sposób jego przechowywania, długość życia, mechanizm odświeżania i reguły sprawdzania po stronie serwera.
Z czego składa się token JWT
Typowy token ma trzy części rozdzielone kropkami:
eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9
.
eyJzdWIiOiIxMjMiLCJyb2xlIjoidXNlciIsImV4cCI6MTc2MDAwMDAwMH0
.
podpis
Każda część jest zakodowana w standardzie Base64URL. To kodowanie przygotowane do bezpiecznego użycia w adresach i nagłówkach HTTP, a nie szyfrowanie.
Header
Nagłówek opisuje token. Zwykle zawiera typ dokumentu, czyli JWT, oraz algorytm użyty do podpisu, na przykład HS256, RS256 albo ES256. Algorytm podany w tokenie nie powinien być ślepo akceptowany przez aplikację. Serwer musi mieć własną, dozwoloną listę algorytmów.
Payload
Payload zawiera tak zwane claims, czyli informacje o tokenie i jego właścicielu. Mogą to być identyfikator użytkownika, wystawca, odbiorca, role oraz daty ważności.
| Claim | Znaczenie |
|---|---|
sub |
Identyfikator podmiotu, zwykle użytkownika |
iss |
Wystawca tokenu |
aud |
Usługa, dla której token jest przeznaczony |
exp |
Moment wygaśnięcia tokenu |
iat |
Moment wystawienia tokenu |
jti |
Unikalny identyfikator tokenu |
Nie umieszczałbym w payloadzie numeru PESEL, hasła, klucza API ani innych poufnych danych. Nawet gdy token jest podpisany, jego treść może zostać odczytana przez klienta lub osobę, która go przechwyciła.
Signature
Podpis powstaje na podstawie nagłówka, payloadu i sekretu lub klucza prywatnego. Jeśli ktoś zmieni rolę zuser na admin, obliczony podpis przestanie się zgadzać. Serwer odrzuci taki token, o ile rzeczywiście przeprowadza pełną weryfikację.
Jak działa logowanie z użyciem JWT
W praktyce cały proces można sprowadzić do kilku etapów. Użytkownik wysyła dane logowania, serwer sprawdza hasło, a po sukcesie generuje token z ograniczonym czasem ważności.
- Klient przesyła login i hasło przez połączenie HTTPS.
- Serwer weryfikuje dane i tworzy access token.
- Token trafia do klienta, najczęściej w bezpiecznym ciasteczku.
- Przy kolejnym żądaniu klient dołącza token.
- Serwer sprawdza podpis, wystawcę, odbiorcę i datę wygaśnięcia.
- Dopiero po pozytywnej walidacji aplikacja wykonuje żądaną operację.
W nagłówku HTTP token bywa przesyłany jako Authorization: Bearer .... W aplikacjach przeglądarkowych często lepszym wyborem jest ciasteczko z flagami HttpOnly, Secure i SameSite, choć wtedy trzeba poprawnie zabezpieczyć aplikację przed CSRF.
Prosty przykład w Pythonie
Biblioteka PyJWT pozwala wygenerować i sprawdzić token. Weryfikując go, jawnie wskazuję algorytm oraz oczekiwane wartości issuer i audience. To drobny szczegół, który odróżnia demonstracyjny kod od rozsądnej implementacji.
import jwt
from datetime import datetime, timedelta, timezone
secret = "bardzo-dlugi-sekret-przechowywany-poza-kodem"
payload = {
"sub": "user-123",
"role": "user",
"iss": "akademiapython-api",
"aud": "web-app",
"exp": datetime.now(timezone.utc) + timedelta(minutes=10)
}
token = jwt.encode(payload, secret, algorithm="HS256")
claims = jwt.decode(
token,
secret,
algorithms=["HS256"],
issuer="akademiapython-api",
audience="web-app"
)
W działającej aplikacji sekret powinien pochodzić ze zmiennej środowiskowej lub menedżera sekretów, a nie z repozytorium. Przy większej liczbie usług wygodniejsze bywają algorytmy asymetryczne, takie jak RS256, ponieważ usługi mogą weryfikować podpis kluczem publicznym bez znajomości prywatnego klucza wystawcy.
JWT a sesja serwerowa i OAuth
JWT często jest przedstawiany jako następca sesji, ale to zbyt duże uproszczenie. Tokeny i klasyczne sesje rozwiązują podobny problem, tylko inaczej rozkładają odpowiedzialność między klienta a serwer.
| Kryterium | JWT | Sesja serwerowa |
|---|---|---|
| Stan po stronie serwera | Minimalny lub brak | Wymagany magazyn sesji |
| Unieważnienie | Trudniejsze przed wygaśnięciem | Zwykle proste, przez usunięcie sesji |
| Skalowanie | Wygodne w wielu usługach | Wymaga współdzielonego magazynu lub sticky sessions |
| Rozmiar żądań | Może rosnąć wraz z liczbą claims | Klient przesyła krótki identyfikator sesji |
Jeżeli aplikacja jest niewielka i potrzebuje natychmiastowego wylogowania użytkownika ze wszystkich urządzeń, klasyczna sesja może być prostsza i bezpieczniejsza. JWT dobrze pasuje do API, mikrousług i sytuacji, w których wiele komponentów musi samodzielnie zweryfikować tożsamość.
OAuth 2.0 nie jest tym samym co JWT. OAuth opisuje sposób delegowania dostępu, a JWT może być formatem tokenu używanego w takim systemie. Mylenie tych pojęć prowadzi do błędnych decyzji projektowych, zwłaszcza przy integracji z zewnętrznym dostawcą tożsamości.
Najczęstsze błędy, które osłabiają bezpieczeństwo
Największe problemy nie wynikają z samego formatu, lecz z niewłaściwej implementacji. W praktyce szczególnie często widzę tokeny z długim terminem ważności, przechowywane w łatwo dostępnym miejscu i akceptowane bez sprawdzenia wszystkich istotnych parametrów.
- Brak HTTPS pozwala przechwycić token podczas transmisji.
- Przechowywanie tokenu w
localStoragezwiększa skutki ataku XSS, bo kod JavaScript może go odczytać. - Brak sprawdzania
exp,isslubaudmoże pozwolić na użycie tokenu w niewłaściwym miejscu. - Akceptowanie dowolnego algorytmu z nagłówka otwiera drogę do niebezpiecznych błędów konfiguracyjnych.
- Umieszczanie ról wyłącznie po stronie klienta nie zapewnia autoryzacji. Uprawnienia zawsze sprawdza serwer.
- Brak rotacji refresh tokenów utrudnia wykrycie i ograniczenie ich kradzieży.
Przeczytaj również: PowerShell od podstaw - Jak zacząć i nie przepłacić?
Jak ustawić rozsądny czas życia
Access token powinien żyć krótko, często od 5 do 15 minut. Dłuższy dostęp można obsłużyć przez refresh token, który przechowuje się ostrożniej i wymienia rotacyjnie. Krótszy czas nie usuwa ryzyka kradzieży, ale ogranicza okno, w którym napastnik może wykorzystać przejęty token.
JWT nie ma wbudowanego przycisku „unieważnij teraz”. Można prowadzić czarną listę identyfikatorów jti, zmienić sekret, używać krótkich access tokenów albo przechowywać stan sesji obok tokenu. Każda z tych metod zwiększa kontrolę, ale odbiera część prostoty, dla której JWT jest wybierany.
Jak podejść do JWT w nowym projekcie
Zaczynam od odpowiedzi na proste pytanie: czy aplikacja naprawdę potrzebuje tokenu bezstanowego? Jeśli nie, sesja serwerowa może wymagać mniej kodu i dać łatwiejsze wylogowanie. Jeżeli JWT jest uzasadniony, projektuję od razu pełną ścieżkę wygasania, odświeżania i reagowania na kradzież.
- Ustal dozwolone algorytmy i odrzuć wszystkie pozostałe.
- Podpisuj token silnym sekretem albo kluczem prywatnym przechowywanym poza kodem.
- Wymagaj
exp, a w systemach wielousługowych także sprawdzaniaissiaud. - Nie wkładaj do payloadu danych poufnych ani nadmiarowych informacji.
- W przeglądarce rozważ ciasteczko HttpOnly i skonfiguruj ochronę CSRF.
- Loguj odrzucenia tokenów, ale nigdy nie zapisuj w logach ich pełnej treści.
- Przetestuj scenariusze wygaśnięcia, zmiany uprawnień i wylogowania ze wszystkich urządzeń.
JWT działa dobrze tylko razem z dobrym projektem
Najkrótsza odpowiedź na pytanie, czym jest JWT, brzmi: to podpisany, przenośny zestaw informacji, który pomaga serwerowi rozpoznać użytkownika lub usługę. Nie jest hasłem, szyfrowanym sejfem ani kompletnym systemem bezpieczeństwa.
Jeśli zapamiętasz jedną zasadę, niech będzie nią ta: token może być wygodny, ale każdą informację z jego payloadu serwer musi traktować jako wiarygodną dopiero po poprawnej weryfikacji podpisu, czasu życia i przeznaczenia. To właśnie te szczegóły, a nie samo użycie skrótu JWT, decydują o bezpieczeństwie aplikacji.
