Przejdź do głównej zawartości

JWT - idea i zastosowanie

JWT (JSON Web Token) to otwarty standard (RFC 7519) definiujacy kompaktowy i samodzielny sposób bezpiecznego przekazywania informacji miedzy stronami jako obiekt JSON. Token może być zweryfikowany i zaufany, ponieważ jest cyfrowo podpisany.

JWT stal się de facto standardem autentykacji w nowoczesnych aplikacjach webowych i API, szczegolnie w architekturach stateless i mikroserwisowych.

JWT składa się z trzech części oddzielonych kropkami:

xxxxx.yyyyy.zzzzz
│ │ │
│ │ └── Signature (podpis)
│ └──────── Payload (dane)
└─────────────── Header (nagłówek)

Zawiera metadane tokena - typ tokena i algorytm podpisu:

{
"alg": "HS256",
"typ": "JWT"
}

Zawiera claims - twierdzenia o podmiocie (uzytkowniku) i dodatkowe dane:

{
"sub": "1234567890",
"name": "Jan Kowalski",
"email": "jan@example.com",
"role": "admin",
"iat": 1516239022,
"exp": 1516242622
}

Standardowe claims:

  • sub (subject) - identyfikator podmiotu
  • iat (issued at) - czas wydania tokena
  • exp (expiration) - czas wygasniecia
  • iss (issuer) - wydawca tokena
  • aud (audience) - odbiorca tokena

Podpis kryptograficzny gwarantujacy integralnosc tokena:

HMACSHA256(
base64UrlEncode(header) + "." +
base64UrlEncode(payload),
secret
)
  1. Użytkownik loguje się - wysyła login i hasło do serwera
  2. Serwer weryfikuje dane - sprawdza użytkownika w bazie
  3. Serwer generuje JWT - tworzy token z danymi użytkownika
  4. Klient otrzymuje token - przechowuje go (localStorage, cookie)
  5. Klient wysyła token - dołącza do każdego zadania w nagłówku
  6. Serwer weryfikuje token - sprawdza podpis i waznosc
  7. Serwer autoryzuje zadanie - na podstawie danych z tokena
┌────────┐ ┌────────┐
│ Klient │ │ Serwer │
└───┬────┘ └───┬────┘
│ │
│ 1. POST /login {email, hasło} │
│ ────────────────────────────────>│
│ │
│ 2. Weryfikacja + generowanie JWT │
│ <─────────────────────────────── │
│ {token: "eyJhbG..."} │
│ │
│ 3. GET /api/profile │
│ Authorization: Bearer eyJhbG..│
│ ────────────────────────────────>│
│ │
│ 4. Weryfikacja podpisu JWT │
│ <─────────────────────────────── │
│ {user: {...}} │
eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.
eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkphbiBLb3dhbHNraSIsInJvbGUiOiJ1c2VyIiwiaWF0IjoxNTE2MjM5MDIyLCJleHAiOjE1MTYyNDI2MjJ9.
SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c
import jwt from 'jsonwebtoken';
const SECRET_KEY = process.env.JWT_SECRET;
function generateToken(user: User): string {
const payload = {
sub: user.id,
email: user.email,
role: user.role
};
const options = {
expiresIn: '1h', // Token wygasa po 1 godzinie
issuer: 'moja-aplikacja'
};
return jwt.sign(payload, SECRET_KEY, options);
}
// Użycie
const token = generateToken({ id: '123', email: 'jan@example.com', role: 'user' });
console.log(token);
import jwt from 'jsonwebtoken';
function verifyToken(token: string): JwtPayload | null {
try {
const decoded = jwt.verify(token, SECRET_KEY);
return decoded as JwtPayload;
} catch (error) {
if (error instanceof jwt.TokenExpiredError) {
console.log('Token wygasł');
} else if (error instanceof jwt.JsonWebTokenError) {
console.log('Nieprawidłowy token');
}
return null;
}
}
// Middleware Express.js
function authMiddleware(req, res, next) {
const authHeader = req.headers.authorization;
if (!authHeader?.startsWith('Bearer ')) {
return res.status(401).json({ error: 'Brak tokena' });
}
const token = authHeader.split(' ')[1];
const payload = verifyToken(token);
if (!payload) {
return res.status(401).json({ error: 'Nieprawidłowy token' });
}
req.user = payload;
next();
}
// UWAGA: To NIE weryfikuje podpisu!
function decodePayload(token: string): object {
const parts = token.split('.');
const payload = parts[1];
const decoded = Buffer.from(payload, 'base64url').toString('utf8');
return JSON.parse(decoded);
}
// Przykład
const data = decodePayload(token);
console.log(data);
// { sub: "123", email: "jan@example.com", role: "user", iat: ..., exp: ... }

Co to oznacza w praktyce:

  • Nigdy nie przechowuj w JWT haseł, tokenow API, danych wrazliwych
  • Uzywaj HTTPS do transmisji tokenow
  • Jeśli potrzebujesz szyfrowania, użyj JWE (JSON Web Encryption)
AlgorytmTypOpis
HS256SymetrycznyJeden tajny klucz dla podpisu i weryfikacji
RS256AsymetrycznyKlucz prywatny do podpisu, publiczny do weryfikacji
ES256AsymetrycznyECDSA - krotsza sygnatura, ta sama siła

Rekomendacja: RS256 dla systemow z wieloma serwisami (każdy ma klucz publiczny), HS256 dla prostszych aplikacji.

  1. Krótki czas waznosci - access token: 15 min, refresh token: 7 dni
  2. Minimalna ilosc danych - tylko niezbedne claims
  3. Bezpieczne przechowywanie - httpOnly cookie lub secure storage
  4. Rotacja kluczy - okresowa zmiana secret/kluczy
  5. Blacklisting - możliwość unieważniania tokenow przed exp
  6. Walidacja algorytmu - nie akceptuj “alg”: “none”
  • JWT to samodzielny token zawierajacy dane użytkownika i podpis
  • Składa się z trzech części: Header, Payload, Signature
  • Jest zakodowany (base64url), ale nie zaszyfrowany
  • Podpis gwarantuje integralnosc, nie poufnosc
  • Idealny do stateless authentication w API i mikroserwisach
  • Wymaga ostroznosci - nie przechowuj danych wrazliwych w payload