Toolypet
Zurück zum Blog
Dev

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

Toolypet Team

Development Team

8 Min. Lesezeit

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

MerkmalBeschreibung
StatelessKeine Session-Speicherung auf dem Server erforderlich
Self-containedAlle benoetigten Informationen sind im Token enthalten
CompactVerwendbar in URLs, HTTP-Headern
SignedManipulation 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"
}
FeldBeschreibung
algSignaturalgorithmus (HS256, RS256, etc.)
typToken-Typ (JWT)

2. Payload (Claims)

{
  "sub": "user123",
  "name": "Max Mustermann",
  "email": "max@example.com",
  "role": "admin",
  "iat": 1708502400,
  "exp": 1708588800
}

Registrierte Claims

ClaimBeschreibungBeispiel
issAussteller (Issuer)"https://auth.example.com"
subBetreff (Subject)"user123"
audZielgruppe (Audience)"https://api.example.com"
expAblaufzeit (Expiration)1708588800
nbfNicht vor (Not Before)1708502400
iatAusgestellt am (Issued At)1708502400
jtiJWT-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

AlgorithmusBeschreibungAnwendungsfall
HS256HMAC + SHA-256Einzelserver, einfache Implementierung
HS384HMAC + SHA-384Hoehere Sicherheit
HS512HMAC + SHA-512Hoechste 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

AlgorithmusBeschreibungAnwendungsfall
RS256RSA + SHA-256Microservices, oeffentliche Verifizierung
RS384RSA + SHA-384Hohe Sicherheitsanforderungen
RS512RSA + SHA-512Hoechste Sicherheitsstufe
ES256ECDSA + P-256Kurze 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

SzenarioEmpfohlener Algorithmus
EinzelserverHS256
MicroservicesRS256
Oeffentliche Verifizierung erforderlichRS256 / ES256
Mobil/IoTES256 (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?

TokenLebensdauerZweck
Access Token15 Min ~ 1 StundeAPI-Authentifizierung
Refresh Token7 ~ 30 TageAccess 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:

  1. Starker Secret: 256 Bit oder mehr zufaellig
  2. Algorithmus-Verifizierung: Whitelist-Ansatz
  3. Kurze Lebensdauer: Access 15 Min, Refresh 7 Tage
  4. Sichere Speicherung: HttpOnly + Secure Cookies
  5. Keine sensiblen Info: Payload kann von jedem dekodiert werden

Verwandte Tools

ToolZweck
JWT DecoderJWT-Dekodierung und Verifizierung
Base64 EncoderBase64-Kodierung/Dekodierung
Hash GeneratorHash-Generierung
JWTAuthentifizierungSicherheitAPIWebentwicklungToken

Über den Autor

Toolypet Team

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.

Web DevelopmentCSS ToolsDeveloper ToolsSEOSecurity