JWT Komplettanleitung 2026 - Struktur, Sicherheit und Best Practices
Von der Struktur und Funktionsweise von JSON Web Token bis zu Sicherheitsschwachstellen und Best Practices. JWT-Authentifizierung mit praktischen Codebeispielen meistern.
Toolypet Team
Development Team
JWT Komplettanleitung 2026
"JWT? Ist das nicht einfach nur ein Token?"
Ja, ist es. Aber wenn dieses "einfache Token" nicht korrekt implementiert wird, wird es zu einem ernsthaften Sicherheitsproblem. Laut Studien von 2026 enthalten 48% des KI-generierten Authentifizierungscodes Sicherheitsschwachstellen.
Diese Anleitung deckt alles ab, von der JWT-Struktur bis zu praktischen Sicherheits-Best-Practices.
Was ist JWT?
JWT (JSON Web Token) ist eine kompakte und eigenstaendige Methode zur sicheren Informationsuebertragung zwischen zwei Parteien.
Hauptmerkmale
| Merkmal | Beschreibung |
|---|---|
| Stateless | Keine Session-Speicherung auf dem Server erforderlich |
| Self-contained | Alle benoetigten Informationen sind im Token enthalten |
| Compact | Verwendbar in URLs, HTTP-Headern |
| Signed | Manipulation kann erkannt werden |
Anwendungsfaelle
- API-Authentifizierung: API-Anfragen mit Bearer-Token
- SSO (Single Sign-On): Authentifizierung zwischen mehreren Diensten teilen
- Informationsaustausch: Uebertragung signierter Daten
- Authorization: Berechtigungs-/Rolleninformationen einschliessen
JWT-Struktur
JWT besteht aus drei Base64URL-kodierten Teilen, getrennt durch . (Punkte).
xxxxx.yyyyy.zzzzz
| | |
Header Payload Signature
1. Header
{
"alg": "HS256",
"typ": "JWT"
}
| Feld | Beschreibung |
|---|---|
alg | Signaturalgorithmus (HS256, RS256, etc.) |
typ | Token-Typ (JWT) |
2. Payload (Claims)
{
"sub": "user123",
"name": "Max Mustermann",
"email": "max@example.com",
"role": "admin",
"iat": 1708502400,
"exp": 1708588800
}
Registrierte Claims
| Claim | Beschreibung | Beispiel |
|---|---|---|
iss | Aussteller (Issuer) | "https://auth.example.com" |
sub | Betreff (Subject) | "user123" |
aud | Zielgruppe (Audience) | "https://api.example.com" |
exp | Ablaufzeit (Expiration) | 1708588800 |
nbf | Nicht vor (Not Before) | 1708502400 |
iat | Ausgestellt am (Issued At) | 1708502400 |
jti | JWT-ID | "abc123" |
Oeffentliche/Private Claims
{
"role": "admin", // Privater Claim
"email": "user@example.com",
"permissions": ["read", "write"]
}
3. Signature
HMACSHA256(
base64UrlEncode(header) + "." +
base64UrlEncode(payload),
secret
)
Signaturalgorithmen
Symmetrischer Schluessel
| Algorithmus | Beschreibung | Anwendungsfall |
|---|---|---|
| HS256 | HMAC + SHA-256 | Einzelserver, einfache Implementierung |
| HS384 | HMAC + SHA-384 | Hoehere Sicherheit |
| HS512 | HMAC + SHA-512 | Hoechste Sicherheitsstufe |
// Node.js - HS256
const jwt = require('jsonwebtoken');
const token = jwt.sign(
{ userId: 123, role: 'admin' },
'your-256-bit-secret', // Mit demselben Secret verifiziert
{ algorithm: 'HS256', expiresIn: '1h' }
);
Asymmetrischer Schluessel
| Algorithmus | Beschreibung | Anwendungsfall |
|---|---|---|
| RS256 | RSA + SHA-256 | Microservices, oeffentliche Verifizierung |
| RS384 | RSA + SHA-384 | Hohe Sicherheitsanforderungen |
| RS512 | RSA + SHA-512 | Hoechste Sicherheitsstufe |
| ES256 | ECDSA + P-256 | Kurze Schluessel, mobil |
// RS256 - Asymmetrisch
const privateKey = fs.readFileSync('private.pem');
const publicKey = fs.readFileSync('public.pem');
// Ausstellen (Private Key)
const token = jwt.sign(payload, privateKey, { algorithm: 'RS256' });
// Verifizieren (Public Key)
const decoded = jwt.verify(token, publicKey, { algorithms: ['RS256'] });
Algorithmus-Auswahlhilfe
| Szenario | Empfohlener Algorithmus |
|---|---|
| Einzelserver | HS256 |
| Microservices | RS256 |
| Oeffentliche Verifizierung erforderlich | RS256 / ES256 |
| Mobil/IoT | ES256 (kurze Schluessel) |
Praktische Implementierung
Node.js (Express)
const express = require('express');
const jwt = require('jsonwebtoken');
const app = express();
const SECRET = process.env.JWT_SECRET; // Aus Umgebungsvariable laden
// Token-Ausstellung
app.post('/login', async (req, res) => {
const { email, password } = req.body;
// Benutzerverifizierung (Beispiel)
const user = await verifyCredentials(email, password);
if (!user) {
return res.status(401).json({ error: 'Invalid credentials' });
}
const token = jwt.sign(
{
sub: user.id,
email: user.email,
role: user.role,
},
SECRET,
{
expiresIn: '1h',
issuer: 'your-app-name',
}
);
res.json({ token });
});
// Middleware-Verifizierung
const authMiddleware = (req, res, next) => {
const authHeader = req.headers.authorization;
if (!authHeader?.startsWith('Bearer ')) {
return res.status(401).json({ error: 'Missing token' });
}
const token = authHeader.split(' ')[1];
try {
const decoded = jwt.verify(token, SECRET, {
issuer: 'your-app-name',
algorithms: ['HS256'],
});
req.user = decoded;
next();
} catch (err) {
return res.status(401).json({ error: 'Invalid token' });
}
};
// Geschuetzte Route
app.get('/protected', authMiddleware, (req, res) => {
res.json({ message: `Hello, ${req.user.email}` });
});
Python (FastAPI)
from fastapi import FastAPI, Depends, HTTPException
from fastapi.security import HTTPBearer, HTTPAuthorizationCredentials
import jwt
from datetime import datetime, timedelta
import os
app = FastAPI()
security = HTTPBearer()
SECRET = os.environ.get("JWT_SECRET")
# Token-Ausstellung
def create_token(user_id: str, role: str) -> str:
payload = {
"sub": user_id,
"role": role,
"iat": datetime.utcnow(),
"exp": datetime.utcnow() + timedelta(hours=1),
}
return jwt.encode(payload, SECRET, algorithm="HS256")
# Token-Verifizierung
def verify_token(credentials: HTTPAuthorizationCredentials = Depends(security)):
token = credentials.credentials
try:
payload = jwt.decode(token, SECRET, algorithms=["HS256"])
return payload
except jwt.ExpiredSignatureError:
raise HTTPException(status_code=401, detail="Token expired")
except jwt.InvalidTokenError:
raise HTTPException(status_code=401, detail="Invalid token")
# Geschuetzter Endpunkt
@app.get("/protected")
def protected_route(user: dict = Depends(verify_token)):
return {"message": f"Hello, {user['sub']}"}
Sicherheitsschwachstellen und Gegenmassnahmen
1. Algorithm None Angriff
// Boesartiger Header
{
"alg": "none",
"typ": "JWT"
}
Gegenmassnahme:
// Erlaubte Algorithmen angeben
jwt.verify(token, secret, { algorithms: ['HS256'] }); // OK
jwt.verify(token, secret); // Gefaehrlich
2. Schwacher Secret Key
// Gefaehrlich
const SECRET = 'secret123';
// Sicher (mindestens 256 Bit)
const SECRET = crypto.randomBytes(32).toString('hex');
3. Offenlegung sensibler Informationen
// Gefaehrlich: Payload kann Base64-dekodiert werden
{
"password": "user_password", // Niemals tun!
"creditCard": "1234-5678-9012-3456"
}
// Sicher
{
"sub": "user123",
"role": "admin"
}
4. Token-Diebstahl
Gegenmassnahmen-Strategien:
- Kurze Ablaufzeit (15 Min ~ 1 Stunde)
- Refresh Token verwenden
- HTTPS erforderlich
- HttpOnly Cookies (XSS-Praevention)
5. JWT Replay-Angriff
// jti (JWT ID) verwenden
const token = jwt.sign({
sub: user.id,
jti: crypto.randomUUID(), // Eindeutige ID
}, SECRET);
// jti-Blacklist auf dem Server verwalten
Access Token + Refresh Token
Warum wird es benoetigt?
| Token | Lebensdauer | Zweck |
|---|---|---|
| Access Token | 15 Min ~ 1 Stunde | API-Authentifizierung |
| Refresh Token | 7 ~ 30 Tage | Access Token erneuern |
Implementierungsbeispiel
// Beide Token bei Login ausstellen
app.post('/login', async (req, res) => {
const user = await verifyCredentials(req.body);
const accessToken = jwt.sign(
{ sub: user.id, type: 'access' },
ACCESS_SECRET,
{ expiresIn: '15m' }
);
const refreshToken = jwt.sign(
{ sub: user.id, type: 'refresh' },
REFRESH_SECRET,
{ expiresIn: '7d' }
);
// Refresh Token als HttpOnly Cookie
res.cookie('refreshToken', refreshToken, {
httpOnly: true,
secure: true,
sameSite: 'strict',
maxAge: 7 * 24 * 60 * 60 * 1000,
});
res.json({ accessToken });
});
// Token-Erneuerung
app.post('/refresh', (req, res) => {
const refreshToken = req.cookies.refreshToken;
try {
const decoded = jwt.verify(refreshToken, REFRESH_SECRET);
const newAccessToken = jwt.sign(
{ sub: decoded.sub, type: 'access' },
ACCESS_SECRET,
{ expiresIn: '15m' }
);
res.json({ accessToken: newAccessToken });
} catch (err) {
res.status(401).json({ error: 'Invalid refresh token' });
}
});
JWT-Debugging
Token-Dekodierung
Fuegen Sie Ihr Token in JWT Decoder ein, um:
- Header zu pruefen
- Payload zu pruefen
- Ablaufzeit zu pruefen
- Signatur zu verifizieren (wenn Secret bereitgestellt wird)
CLI-Dekodierung
# Header dekodieren
echo "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9" | base64 -d
# Payload dekodieren
echo "eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4ifQ" | base64 -d
Best Practices Checkliste
Ausstellung
- Starker Secret Key (256 Bit oder mehr)
- Algorithmus angeben (HS256, RS256)
- Kurze Ablaufzeit (15 Min ~ 1 Stunde)
- Erforderliche Claims einschliessen (sub, iat, exp, iss)
- Keine sensiblen Informationen
Verifizierung
- Algorithmus-Whitelist (
algorithms: ['HS256']) - Ablaufzeit-Validierung
- Aussteller (iss) Validierung
- Zielgruppe (aud) Validierung
Speicherung und Uebertragung
- HTTPS erforderlich
- HttpOnly Cookie (XSS-Praevention)
- SameSite-Attribut (CSRF-Praevention)
- localStorage vermeiden (XSS-anfaellig)
Haeufig gestellte Fragen
F1: JWT vs Session, wann welches verwenden?
A:
- JWT: Stateless API, Microservices, Mobile Apps
- Session: Traditionelle Web-Apps, Server-seitiges Rendering, sofortiges Logout erforderlich
F2: Was passiert, wenn JWT gestohlen wird?
A: Access Token bleibt bis zum Ablauf gueltig. Daher:
- Kurze Ablaufzeit setzen (15 Min)
- Refresh Token Rotation
- Alle Token bei Verdacht ungueltig machen
F3: Warum sollte ich nicht in localStorage speichern?
A: Es ist anfaellig fuer XSS-Angriffe. Da JavaScript darauf zugreifen kann, koennen boesartige Skripte Token stehlen. HttpOnly Cookies sind sicherer.
F4: Ist RS256 sicherer als HS256?
A: Es ist nicht "sicherer", sondern "anderer Zweck".
- HS256: Gleicher Secret geteilt, einzelner Server
- RS256: Mit oeffentlichem Schluessel verifizieren, mehrere Dienste
F5: Brauche ich eine Token-Blacklist?
A: Wenn sofortiges Logout erforderlich ist, ja. Aber es reduziert den Vorteil von Stateless. Kurze Ablaufzeit + Refresh Token ist eine Alternative.
Fazit
JWT-Sicherheits-Kernpunkte:
- Starker Secret: 256 Bit oder mehr zufaellig
- Algorithmus-Verifizierung: Whitelist-Ansatz
- Kurze Lebensdauer: Access 15 Min, Refresh 7 Tage
- Sichere Speicherung: HttpOnly + Secure Cookies
- Keine sensiblen Info: Payload kann von jedem dekodiert werden
Verwandte Tools
| Tool | Zweck |
|---|---|
| JWT Decoder | JWT-Dekodierung und Verifizierung |
| Base64 Encoder | Base64-Kodierung/Dekodierung |
| Hash Generator | Hash-Generierung |
Über den Autor
Toolypet Team
Development Team
The Toolypet Team creates free, privacy-focused web tools for developers and designers. All tools run entirely in your browser with no data sent to servers.