Jak zdekodować JWT token: kompletny przewodnik dla deweloperów
API właśnie zwróciło 401 Unauthorized. Nagłówek Authorization: Bearer eyJhbGciOi... wygląda poprawnie. Czy token wygasł, czy audience był zły, a może issuer obrócił klucz? Nie da się odpowiedzieć na to pytanie bez przeczytania, co faktycznie znajduje się w środku — a żeby zdekodować JWT token, nie potrzeba ani sekretu, ani biblioteki, ani nawet połączenia z siecią. JWT to trzy fragmenty zakodowane w base64url, połączone kropkami. Dekodowanie jest mechaniczne: split, base64url, JSON.parse. Bez magii, bez kryptografii.
Ten przewodnik prowadzi przez anatomię tokenu, pokazuje, jak zdekodować JWT w Node.js, Pythonie, Go i przeglądarce, omawia różnicę między dekodowaniem a weryfikacją, na której potyka się większość zespołów, oraz wymienia realne tryby awarii, które prędzej czy później ugryzą. Jeśli trzeba szybko podejrzeć token, wystarczy skoczyć do naszego darmowego dekodera JWT. Działa w całości w przeglądarce, więc tokeny produkcyjne nigdy nie opuszczają urządzenia.
Czym jest JWT? (krótka anatomia)
JSON Web Token (JWT) to zwięzły, bezpieczny dla URL credential opisany w RFC 7519. Przenosi claim, czyli dane o użytkowniku i o samym tokenie, między dwiema stronami. JWT składa się z trzech fragmentów zakodowanych w base64url i połączonych kropkami: header, payload i signature.
Oto prawdziwy token rozłożony na części, by widoczna była struktura:
eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9 ← header
.
eyJzdWIiOiJ1c2VyXzEyMyIsImV4cCI6MTk5OTk5OTk5OX0 ← payload
.
4NhxPjwoZxPNuxG-2C5ugGxaUsUJ0QyskAz7Ymz5Sg0 ← signature
Header opisuje sposób podpisania tokenu, najczęściej { "alg": "HS256", "typ": "JWT" }. Payload przenosi claim: zarejestrowane jak sub, exp, iat plus własne, takie jak role czy tenant. Signature to kryptograficzny dowód obliczony nad headerem i payloadem, który pozwala odbiorcy wykryć modyfikację. Base64url to bezpieczny dla URL wariant base64; przystępne wprowadzenie w dziesięć minut znajduje się w naszym przewodniku po Base64.
JWT można spotkać wszędzie tam, gdzie żyje nowoczesna autoryzacja: access token OAuth 2.0, ID token OpenID Connect, credential API tworzone przez Auth0, Okta, Clerk, Supabase, Firebase oraz tokeny przekazywane między mikroserwisami w obrębie mesh. To domyślny format credential ostatniej dekady.
Jedna rzecz, którą warto zapamiętać, zanim pójdziemy dalej: JWT są zakodowane, a nie zaszyfrowane. Każdy, kto trzyma token, może odczytać każdy claim. Signature potwierdza pochodzenie; nie ukrywa zawartości. Ten jeden fakt dyktuje wszystko, co dalej: co bezpiecznie umieścić w payloadzie, dlaczego dekodowanie nie wymaga sekretu i dlaczego weryfikacja signature po stronie serwera jest nienegocjowalna.
Jak działa dekodowanie JWT (base64url, nie deszyfrowanie)
Dekodowanie JWT to nie operacja kryptograficzna. To cztery mechaniczne kroki:
- Podziel token na
.na dokładnie trzy segmenty. - Zdekoduj pierwszy segment z base64url i sparsuj go jako JSON. To header.
- Zdekoduj drugi segment z base64url i sparsuj go jako JSON. To payload.
- Trzeci segment (signature) zostaw jako surowe bajty. Jego weryfikacja wymaga klucza.
To cały algorytm. Żadna biblioteka nie jest obowiązkowa. Każdy język z base64 i parserem JSON zdekoduje JWT w pięciu liniach. Nasz koder/dekoder Base64 wykona kroki 2 i 3 ręcznie, jeśli ktoś chce zobaczyć mechanikę z bliska.
Czym jest base64url?
Base64url to zwykły base64 z trzema poprawkami, by wynik był bezpieczny w URL i nagłówkach HTTP: - zastępuje +, _ zastępuje /, a wypełnienie końcowe = zostaje porzucone. Jeśli surowy base64url trafi do standardowego dekodera base64 bez odwrócenia tych podstawień, w wyniku pojawia się albo śmieć, albo błąd. Zaawansowany przewodnik po Base64 omawia szczegółowo przypadki brzegowe wypełnienia.
| Standardowy base64 | base64url | |
|---|---|---|
| Alfabet | A-Z a-z 0-9 + / | A-Z a-z 0-9 - _ |
| Wypełnienie | Wymagane = na końcu | Porzucone |
| Bezpieczny dla URL? | Nie | Tak |
| Przykład | PDw/Pz8+ | PDw_Pz8- |
Jeszcze jedna sprawa, którą warto powiedzieć wprost: po stronie klienta nie da się odszyfrować signature. Dekodowanie jest jednokierunkowe — od zakodowanych bajtów do JSON. Weryfikacja signature to osobna operacja, która wymaga albo sekretu HMAC (dla rodziny algorytmów HS), albo klucza publicznego issuera (dla RS, PS, ES, EdDSA).
Dlaczego do dekodowania nie potrzeba sekretu
Bo payload to base64url plus JSON, a nie szyfrogram. Sekret pojawia się dopiero wtedy, gdy chcemy udowodnić, że token nie został zmodyfikowany — to jest właśnie sprawdzenie signature. Każdy na drodze sieciowej, każdy, kto trzyma token w linii logu, każdy z przeglądarką może odczytać każdy claim, jaki tam włożyliśmy. Dlatego nigdy nie wolno umieszczać w payloadzie JWT haseł, kluczy API ani PII wykraczających poza to, co odbiorca już zna. Szerszy model zagrożeń znajduje się w naszych najlepszych praktykach bezpieczeństwa.
Zdekoduj JWT online w 3 kliknięciach: darmowy dekoder JWT
Czasem trzeba po prostu mieć odpowiedź już teraz. Czy ten token wygasł, czy claim aud jest tym, co myślę, czy header mówi alg:none? Najszybsza droga to nasz dekoder JWT online. Został zbudowany pod ścieżkę reakcji na incydent o 2 w nocy.
- Wklej cały token do pola wejściowego. Razem z trzema segmentami rozdzielonymi kropkami.
- Przeczytaj zdekodowany header, payload i statusowe chipsy na górze: algorytm, czas wystawienia, wygaśnięcie oraz czerwoną plakietkę
Expired, jeśliexpjest już w przeszłości. - Skopiuj potrzebny panel do raportu o błędzie, wątku na Slacku albo do fixture testowego.
Dlaczego można bezpiecznie wkleić tu prawdziwe tokeny produkcyjne:
- 100% w przeglądarce. Dekodowanie odbywa się przez natywne
atobiJSON.parse. Bez żadnego żądania sieciowego. - Bez logowania, bez śledzenia, bez ciasteczek, bez rejestracji.
- Działa offline po jednorazowym załadowaniu strony.
Dekoder JWT jest niezależny od algorytmu. Ponieważ dekodowanie potrzebuje tylko base64url i JSON, czyta każdy wariant JWS: HS256/384/512, RS256/384/512, PS256/384/512, ES256/384/512, EdDSA i alg:none. Tylko weryfikacja signature zależy od algorytmu — a weryfikacji nie powierza się publicznemu narzędziu webowemu. Więcej o tym za chwilę.
Trzeba zdekodować segment ręcznie, by porównać wynik narzędzia? Wystarczy nasz koder/dekoder Base64 i podanie każdego segmentu jako base64url.
Jak zdekodować JWT w kodzie (Node.js, Python, Go, przeglądarka)
Do wszystkiego poza interaktywnym debugowaniem — czyli middleware, testów, skryptów migracyjnych, narzędzi CLI — sięga się po bibliotekę. Poniżej minimalny kod do dekodowania JWT w czterech środowiskach, w których najczęściej da się trafić, ze ścieżką wyłącznie odczytu obok ścieżki weryfikującej. Każdy fragment można skopiować jeden do jednego i daje wyniki pokazane w komentarzach.
Dekodowanie JWT w Node.js (jsonwebtoken)
// npm install jsonwebtoken
const jwt = require('jsonwebtoken');
const token = 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9' +
'.eyJzdWIiOiJ1c2VyXzEyMyIsImV4cCI6MTk5OTk5OTk5OX0' +
'.4NhxPjwoZxPNuxG-2C5ugGxaUsUJ0QyskAz7Ymz5Sg0';
// Tylko dekodowanie — NIE weryfikuje signature
const decoded = jwt.decode(token, { complete: true });
console.log(decoded.header); // { alg: 'HS256', typ: 'JWT' }
console.log(decoded.payload); // { sub: 'user_123', exp: 1999999999 }
// Weryfikacja — ścieżka produkcyjna
const secret = process.env.JWT_SECRET;
const verified = jwt.verify(token, secret, { algorithms: ['HS256'] });
Do verify zawsze przekazuj jawną listę dozwolonych algorithms. Pominięcie jej historycznie pozwalało atakującym zdegradować token RS256 do HS256 poprzez podpisanie kluczem publicznym jako sekretem HMAC — to klasyczny atak na pomieszanie algorytmów. Allowlist jest obroną.
Dekodowanie JWT w Pythonie (PyJWT)
# pip install PyJWT
import jwt
token = (
"eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9"
".eyJzdWIiOiJ1c2VyXzEyMyIsImV4cCI6MTk5OTk5OTk5OX0"
".4NhxPjwoZxPNuxG-2C5ugGxaUsUJ0QyskAz7Ymz5Sg0"
)
# Tylko dekodowanie — niebezpieczne dla auth, dobre do podglądu
decoded = jwt.decode(token, options={"verify_signature": False})
print(decoded) # {'sub': 'user_123', 'exp': 1999999999}
# Header bez tknięcia payloadu
header = jwt.get_unverified_header(token)
print(header) # {'alg': 'HS256', 'typ': 'JWT'}
# Weryfikacja — ścieżka produkcyjna
payload = jwt.decode(
token,
key="your-hs256-secret",
algorithms=["HS256"],
audience="api.example.com",
)
PyJWT odmawia weryfikacji bez listy algorithms — to rozsądny domyślny zachowanie, które blokuje ten sam atak na pomieszanie, przed którym ostrzega przykład w Node.
Dekodowanie JWT w Go (golang-jwt/jwt/v5)
// go get github.com/golang-jwt/jwt/v5
package main
import (
"fmt"
"github.com/golang-jwt/jwt/v5"
)
func main() {
tokenString := "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9" +
".eyJzdWIiOiJ1c2VyXzEyMyIsImV4cCI6MTk5OTk5OTk5OX0" +
".4NhxPjwoZxPNuxG-2C5ugGxaUsUJ0QyskAz7Ymz5Sg0"
// Tylko dekodowanie
parser := jwt.NewParser()
claims := jwt.MapClaims{}
_, _, err := parser.ParseUnverified(tokenString, claims)
if err != nil {
panic(err)
}
fmt.Println(claims["sub"], claims["exp"]) // user_123 1.999999999e+09
// Weryfikacja
secret := []byte("your-hs256-secret")
token, err := jwt.Parse(tokenString, func(t *jwt.Token) (interface{}, error) {
if _, ok := t.Method.(*jwt.SigningMethodHMAC); !ok {
return nil, fmt.Errorf("unexpected alg: %v", t.Header["alg"])
}
return secret, nil
})
fmt.Println(token.Valid, err)
}
Domknięcie keyFunc to miejsce, w którym wymusza się rodzinę algorytmów. Zanim odda się klucz, należy odrzucić wszystko, co nie jest oczekiwaną metodą.
Dekodowanie JWT w przeglądarce (zero zależności)
Czasem nie chce się żadnej zależności: szybki panel debug, rozszerzenie przeglądarki, mała plakietka UI pokazująca aktualną rolę użytkownika. Natywne API przeglądarki w pełni wystarczają.
function decodeJwt(token) {
const [h, p] = token.split('.');
const pad = (s) => s + '==='.slice((s.length + 3) % 4);
const decodeSegment = (s) => {
const b64 = pad(s).replace(/-/g, '+').replace(/_/g, '/');
const bytes = Uint8Array.from(atob(b64), (c) => c.charCodeAt(0));
return JSON.parse(new TextDecoder().decode(bytes));
};
return { header: decodeSegment(h), payload: decodeSegment(p) };
}
const { header, payload } = decodeJwt(token);
console.log(header); // { alg: 'HS256', typ: 'JWT' }
console.log(payload); // { sub: 'user_123', exp: 1999999999 }
Przejście przez TextDecoder ma znaczenie dla każdego tokenu z payloadem zawierającym znaki spoza ASCII (emoji w wyświetlanej nazwie, cyrylica w preferred_username). Zwykłe atob zwraca ciąg binarny, na którym JSON.parse zacina się przy wielobajtowym UTF-8. Dokładnie to robi nasz dekoder JWT online lokalnie w przeglądarce — minus UI.
Tabela porównawcza
| Język | Tylko dekodowanie | Weryfikacja | Biblioteka |
|---|---|---|---|
| Node.js | jwt.decode(token) | jwt.verify(token, key, { algorithms: [...] }) | jsonwebtoken |
| Python | jwt.decode(token, options={"verify_signature": False}) | jwt.decode(token, key, algorithms=[...]) | PyJWT |
| Go | parser.ParseUnverified(token, claims) | jwt.Parse(token, keyFunc) | golang-jwt/jwt/v5 |
| Przeglądarka | atob + TextDecoder + JSON.parse | Pytanie do backendu | — |
Dekodowanie a weryfikacja: kluczowa różnica
Dekodowanie JWT czyta jego claim; weryfikacja JWT dowodzi, że te claim nie zostały zmodyfikowane. Dekodowanie nigdy nie ufa; weryfikacja jest zaufaniem. To jedna jedyna różnica, która oddziela działającą implementację autoryzacji od CVE.
| Dekodowanie | Weryfikacja | |
|---|---|---|
| Wymaga sekretu/klucza? | Nie | Tak |
| Działa po stronie klienta? | Bezpiecznie | Nigdy |
| Dowodzi autentyczności? | Nie | Tak |
| Sprawdza wygaśnięcie? | Opcjonalnie | Tak |
| Zastosowanie | Debug, podgląd | Uwierzytelnianie, autoryzacja |
Nigdy nie należy podejmować decyzji o autoryzacji na podstawie zdekodowanego (niezweryfikowanego) JWT. Ani w middleware, ani w hooku Reacta, ani w funkcji serverless, o której zakłada się, że stoi za bramą. Zdekodowane claim mówią, co token deklaruje; zweryfikowane claim mówią, co issuer podpisał. Atakujący, który podsuwa serwerowi ręcznie skonstruowany token bez ważnej signature, może wstawić w payload, co tylko zechce — i tylko sprawdzenie signature go odrzuci.
Jeszcze jeden szczegół o rodzinie HMAC: jeśli używa się HS256, entropia sekretu rozstrzyga całą grę. Krótki, łatwy do zgadnięcia sekret poddaje się brute-force offline na dowolnym tokenie, który atakujący przechwyci, a wtedy zaczyna sam wystawiać tokeny i wchodzi frontowymi drzwiami. Należy używać co najmniej 256 bitów prawdziwej losowości. Arytmetykę, dlaczego ma to znaczenie, opisuje przewodnik po entropii hasła.
Częste claim w JWT — krótki słownik
W każdym napotkanym JWT używana jest jakaś podzbiór zarejestrowanych claim z RFC 7519. Warto zapamiętać ten krótki spis:
| Claim | Nazwa | Przykład | Uwagi |
|---|---|---|---|
iss | Issuer | https://auth.example.com | Kto wystawił token |
sub | Subject | user_123 | Zwykle ID użytkownika |
aud | Audience | api.example.com | Dla kogo token jest przeznaczony — musi się zgadzać na serwerze |
exp | Wygaśnięcie | 1715003600 | Sekundy Unix; przeszłość = wygasłe |
iat | Czas wystawienia | 1715000000 | Sekundy Unix, w których token został wystawiony |
nbf | Not Before | 1715000060 | Najwcześniejszy moment, od którego token jest użyteczny |
jti | JWT ID | d1f8… | Unikalny dla tokenu; chroni przed powtórzeniem |
kid | Key ID (header) | key-2025-01 | Który klucz w JWKS podpisał ten token |
Obok tych standardowych żyją claim specyficzne dla aplikacji: role, scope, email, tenant_id — cokolwiek emituje dostawca tożsamości. Warto trzymać je krótkie. Każdy bajt jedzie razem z każdym żądaniem.
Aby odczytać ludzkie daty z iat i exp, można sięgnąć po nasz konwerter Unix timestamp. Wkleja się liczbę, dostaje datę w lokalnej strefie czasowej i w sekundę widzi błąd ze skewą zegara.
Rozwiązywanie problemów: dlaczego mój JWT się nie dekoduje?
Pięć realnych trybów awarii, w przybliżonej kolejności częstotliwości. Każdy w schemacie Objaw → Przyczyna → Naprawa.
- „Invalid JWT format, expected three segments”. Skopiowano tylko payload albo powłoka zawinęła token na kilka linii i przechwycono tylko pierwszą. Naprawa: ponownie skopiować pełną wartość
xxx.yyy.zzzz oryginalnego ciała odpowiedzi, a nie z renderowanego terminala. Długie wartości w jednej linii lepiej przeżywają w zakładce Network devtools przeglądarki niż w przewijanym terminalu. - Pięć segmentów zamiast trzech. Mamy do czynienia z JWE (zaszyfrowanym JWT), nie z JWS. Format brzmi
header.encryptedKey.iv.ciphertext.tag. Dekoder odczyta header, ale payload to szyfrogram. Naprawa: zdekodowanie payloadu wymaga klucza deszyfrującego, którym zwykle zajmuje się serwerowy SDK auth, a nie narzędzie do debugowania. - Błąd base64url na pozornie prawidłowym tokenie. Token został gdzieś po drodze zakodowany URL — w ciasteczku, redirect URL, w przechwyconym logu proxy. W ciągu widać dosłowne
%2Elub%2B. Naprawa: najpierw zdekodować URL, a dopiero potem podać wynik do dekodera JWT. - Błąd parsowania JSON na payloadzie. Terminal albo komunikator wstawił miękkie złamania linii, albo skrypt wkleił „cudzysłowy drukarskie” wokół identyfikatora. Naprawa: wyświetlić surowe bajty odpowiedzi (curl z
-o file.txtalbo widok Raw w devtools), wyciąć białe znaki i wkleić ponownie. - Dekoduje się czysto, ale backend i tak odrzuca. To nie jest problem dekodowania, tylko weryfikacji. Token jest strukturalnie poprawny; coś, co serwer sprawdza (signature,
aud,exp, skew zegara, lookup pokid), zawodzi. Skok do następnego rozdziału.
Dwa wyróżnienia honorowe, które nie są błędami parsowania, ale warto je wyłapać przy okazji otwartego dekodera: wartość alg ustawiona na none w headerze (na produkcji traktować jako wrogą) oraz wartość exp w przeszłości. Dekoder mimo to pokazuje claim, by można było debugować — to prawidłowe zachowanie — a nasze narzędzie sygnalizuje to czerwoną plakietką Expired.
Gdy dekodowanie nie wystarczy: weryfikacja signature
Dekodowanie kończy się na „oto co token deklaruje”. Weryfikacja jest tym, co zamienia deklarację w decyzję o zaufaniu. Signature to dowód obliczony kluczem prywatnym issuera lub współdzielonym sekretem, który wiąże header z payloadem. Zmiana jednego bajtu — i sprawdzenie signature się sypie. Bez niego każdy, kto może zrobić POST na endpoint, ręcznie skonstruuje token „admina” poprzez zmianę payloadu i pominięcie signature.
Nigdy nie akceptuj alg:none.
Produkcyjna weryfikacja, w każdym języku i framework, wygląda mniej więcej według tej listy. Brak każdego z punktów warto traktować jako błąd:
- Należy podać jawną allowlist
algorithms: ['RS256'](lub jakikolwiek algorytm, który stosujesz). Pokonuje to ataki na pomieszanie algorytmów. - Sprawdź, czy
audzgadza się z identyfikatorem usługi, aissz oczekiwanym URL issuera. - Porównaj
expz czasem bieżącym, dopuszczając najwyżej 60 sekund tolerancji na skew zegara. - Przy rotacji kluczy odszukaj klucz publiczny po
kidz endpointu JWKS. Nigdy nie przybijaj jednego klucza na zawsze. - Skutecznie unieważniaj, trzymając
expkrótko (minuty, nie dni) i opcjonalnie utrzymując denylistjtidla tokenów o wysokiej wartości.
Każda licząca się biblioteka JWT wystawia te punkty jako opcje pojedynczego wywołania. Jeśli kod weryfikujący ich nie ustawia, zostawia się włączone domyślne — a domyślne historycznie były błędem. Pełny model zagrożeń znajduje się w najlepszych praktykach bezpieczeństwa.
FAQ
Czy można zdekodować JWT bez tajnego klucza?
Tak. Header i payload są zakodowane w base64url, a nie zaszyfrowane, więc każdy, kto trzyma token, może odczytać jego claim. Sekret lub klucz publiczny jest wymagany tylko do weryfikacji signature. Tak jest z założenia: payload ma być czytelny, by odbiorca mógł podejmować decyzje o autoryzacji.
Czy bezpiecznie jest wkleić produkcyjny JWT do dekodera online?
Tylko wtedy, gdy dekoder działa w przeglądarce i nigdy nie wysyła tokenu. Nasz dekoder JWT parsuje lokalnie przez natywne atob i JSON.parse; nic nie idzie na żaden serwer. Zdalne debugery, które POST-ują token do API, należy traktować jak wyciek danych uwierzytelniających.
Jaka jest różnica między dekodowaniem a weryfikacją JWT?
Dekodowanie tylko czyta claim. Nie potrzebuje klucza i niczego nie dowodzi. Weryfikacja sprawdza signature względem klucza issuera i potwierdza, że token nie został zmodyfikowany. Nigdy nie podejmuj decyzji uwierzytelniającej na podstawie zdekodowanego, ale niezweryfikowanego tokenu.
Mój JWT wygląda na ucięty. Co liczy się jako poprawny format?
Poprawny JWT ma dokładnie trzy segmenty base64url rozdzielone kropkami: header.payload.signature. Pięć segmentów oznacza zaszyfrowany JWT (JWE), nie JWS. Zero kropek oznacza, że skopiowano tylko jeden segment z zawiniętej linii w terminalu.
Dlaczego dekoder pokazuje token, który wygasł?
Dekoder czyta claim niezależnie od ważności, by można było debugować odrzucenia. Tylko weryfikator odmawia tokenom wygasłym. Nasze narzędzie eksponuje plakietkę Expired, porównując exp z lokalnym zegarem, więc problem widać natychmiast — bez mrużenia oczu nad timestampami Unix.
Które algorytmy można dekodować?
Wszystkie. Dekodowanie potrzebuje tylko base64url i parsowania JSON, więc jest niezależne od algorytmu. Obejmuje to HS256/384/512, RS256/384/512, PS256/384/512, ES256/384/512, EdDSA i alg:none. Tylko weryfikacja zależy od wybranego algorytmu.
Czy w Node.js używać jwt-decode czy jsonwebtoken?
jwt-decode na frontendzie, gdy wystarcza sam odczyt payloadu — na przykład pokazanie nazwy użytkownika z access tokenu. jsonwebtoken na backendzie, bo tylko backend może trzymać klucz podpisujący i wykonać jwt.verify. Nigdy nie weryfikuj na kliencie.
Podsumowanie
Dekodowanie JWT nie jest tak tajemnicze, jak sugeruje określenie „token kryptograficzny”. Pięć wniosków i nigdy więcej nie zostanie się z nieprzeniknionym ciągiem eyJhbGciOi…:
- Dekodowanie to base64url plus JSON parse. Bez sekretu.
- JWT ma trzy części (header, payload, signature) połączone kropkami.
- Dekodowanie nigdy nie dowodzi autentyczności. Zawsze weryfikuj po stronie serwera kluczem issuera.
- Odrzucaj
alg:nonei zawsze przekazuj jawną allowlist algorytmów doverify. - Nigdy nie umieszczaj w payloadzie haseł, kluczy prywatnych ani wrażliwych PII. Czyta je każdy, kto trzyma token.
Warto zachować w zakładkach nasz darmowy dekoder JWT — przyda się przy dyżurach on-call. Wkleisz token, przeczytasz claim i w sekundę wychwycisz wygaśnięcie, a token nigdy nie opuści przeglądarki.