Was ein JWT eigentlich ist
Ein JSON Web Token ist ein kompakter, URL-sicherer String, der eine Reihe von Claims zusammen mit einer Signatur über diese kodiert. Er ist durch RFC 7519 definiert und basiert auf zwei ergänzenden Spezifikationen: JSON Web Signature (JWS) für die Signierung und JSON Web Encryption (JWE) für die Vertraulichkeit. Fast jeder JWT, dem man in der Praxis begegnet, ist ein JWS.
Der Token besteht aus drei Base64url-kodierten Teilen, die durch Punkte getrennt sind: Header, Payload und Signatur. Er ist self-contained, was bedeutet, dass alles, was ein Server für eine Entscheidung benötigt, mit der Anfrage übermittelt wird. Die Validierung erfordert keinen Datenbank-Lookup, keinen gemeinsamen Session-Store und keinen Aufruf beim Issuer.
Hierbei ist es wichtig, präzise zu sein, was genau dadurch bewiesen wird. Ein JWT belegt, dass die Instanz, die ihn ausgestellt hat, genau diese Payload signiert hat. Er beweist nicht, dass der Token für Sie bestimmt war, es sei denn, Sie prüfen das Audience-Feld. Er beweist nicht, dass der Benutzer immer noch berechtigt ist, eine Aktion auszuführen, es sei denn, Sie prüfen Scopes und Rollen. Und er verbirgt keinerlei Informationen, es sei denn, Sie verwenden JWE. Jede Sicherheitseigenschaft, die für Sie relevant ist, muss explizit geprüft werden.
Die drei Teile entschlüsselt
Der Header ist ein kleines JSON-Objekt, das den Signieralgorithmus und den Token-Typ benennt. Das Feld alg ist dabei das entscheidende. typ ist fast immer JWT, und kid gibt an, welcher Schlüssel verwendet wurde, damit Verifizierer bei einer Schlüsselrotation den richtigen finden können.
{ "alg": "HS256", "typ": "JWT", "kid": "2026-09" }
Der Payload ist ein JSON-Objekt aus Claims. Registrierte Claims haben standardisierte Namen, die in der Spezifikation definiert sind: iss für den Issuer, sub für das Subject, aud für die Audience, exp für das Ablaufdatum (Expiration), nbf für „Not Before“, iat für den Ausstellungszeitpunkt (Issued At) und jti für eine eindeutige Token-ID. Alles andere sind benutzerdefinierte Claims, die ihr selbst festlegt.
{
"iss": "https://auth.example.com",
"sub": "user_42",
"aud": "api.example.com",
"exp": 1760000000,
"iat": 1759999100,
"scope": "read:posts write:posts",
"role": "editor"
}
Die Signatur wird über das Base64url-Format des Headers und des Payloads berechnet. Ändert man auch nur ein einziges Zeichen in einem der beiden Teile, stimmt die neu berechnete Signatur nicht mehr überein. Diese Eigenschaft macht ein JWT sicher für die Übergabe an einen nicht vertrauenswürdigen Client und ist das einzige Hindernis zwischen einem legitimen Claim und einer Fälschung.
Signiert, nicht verschlüsselt
Das häufigste Missverständnis bei JWTs ist, dass sie geheim seien. Das sind sie nicht. Der Payload ist Base64url-kodiert – das ist eine Kodierung, keine Verschlüsselung. Jeder, der den Token besitzt, kann jeden Claim mit einer einzigen Zeile Code dekodieren.
const [, payload] = token.split(".");
console.log(JSON.parse(atob(payload)));
// { sub: "user_42", role: "editor", scope: "read:posts" }
Das hat zwei Konsequenzen. Erstens: Packen Sie niemals Geheimnisse, Passwörter oder personenbezogene Daten in einen JWT, die Sie dem Client nicht gerne zeigen würden. Zweitens: Behandeln Sie den Token selbst als Anmeldedaten (Credential): Der Besitz des Tokens reicht aus, um als das entsprechende Subject aufzutreten. Genau deshalb sind die Speicherung und der Transport später in diesem Guide so wichtig.
Wenn Sie den Payload tatsächlich vor dem Client verbergen müssen, verwenden Sie JSON Web Encryption und eine entsprechende Library. Für die überwältigende Mehrheit der Systeme ist ein signierter JWS über TLS die richtige Lösung; eine zusätzliche Verschlüsselung würde lediglich die Komplexität erhöhen.
Signieralgorithmen: HS256 vs. RS256
In realen Deployments dominieren zwei Algorithmen-Familien.
HS256 ist HMAC mit SHA-256. Dasselbe Secret wird sowohl zum Signieren als auch zum Verifizieren verwendet. Er ist schnell, einfach und ideal, wenn ein einziger Service seine eigenen Token sowohl ausstellt als auch verifiziert.
import { SignJWT, jwtVerify } from "jose";
const secret = new TextEncoder().encode(process.env.JWT_SECRET);
const token = await new SignJWT({ role: "editor" })
.setProtectedHeader({ alg: "HS256" })
.setSubject("user_42")
.setExpirationTime("15m")
.sign(secret);
await jwtVerify(token, secret, { algorithms: ["HS256"] });
RS256 ist RSA mit SHA-256 und ES256 ist ECDSA über einer Prime Curve. Der Issuer besitzt einen privaten Schlüssel und signiert damit; alle anderen besitzen den öffentlichen Schlüssel und verifizieren die Signatur. Diese Asymmetrie ist der Grund, warum große Systeme diesen Ansatz bevorzugen: Ein Resource Server kann Token verifizieren, ohne selbst in der Lage zu sein, sie zu erstellen. ES256 bietet die gleiche Garantie bei wesentlich kleineren Schlüsseln und Signaturen.
import { importPKCS8, importSPKI, SignJWT, jwtVerify } from "jose";
const privateKey = await importPKCS8(process.env.JWT_PRIVATE_KEY!, "RS256");
const publicKey = await importSPKI(process.env.JWT_PUBLIC_KEY!, "RS256");
const token = await new SignJWT({ role: "editor" })
.setProtectedHeader({ alg: "RS256", kid: "2026-09" })
.setSubject("user_42")
.setExpirationTime("15m")
.sign(privateKey);
await jwtVerify(token, publicKey, {
algorithms: ["RS256"],
issuer: "https://auth.example.com",
audience: "api.example.com",
});
Die wichtigste Regel, unabhängig von der Wahl des Algorithmus: Der Verifizierer muss den erwarteten Algorithmus fest vorgeben (pinning). Lassen Sie niemals den Header des Tokens selbst entscheiden, wie die Prüfung durchgeführt wird.
Claims: registriert und benutzerdefiniert
Registrierte Claims sind durch die Spezifikation reserviert und werden von jeder ernsthaften Library unterstützt.
iss— wer das Token ausgestellt hat. Prüfen Sie dies, um Tokens aus einer anderen Umgebung abzulehnen.sub— auf wen sich das Token bezieht, normalerweise die User-ID.aud— für wen das Token bestimmt ist. Ein Token, das für Ihre öffentliche API erstellt wurde, sollte nicht von Ihrer Admin-API akzeptiert werden.exp— wann das Token abläuft, als Unix-Timestamp. Setzen Sie diesen Wert immer.nbf— nicht vor diesem Zeitpunkt gültig. Selten benötigt, aber nützlich für gestaffelte Rollouts.iat— wann es ausgestellt wurde. Praktisch für Prüfungen des maximalen Alters und zum Debugging.jti— eine eindeutige ID für dieses Token, verwendet zur Erkennung von Replay-Attacken und für Deny-Lists.
Benutzerdefinierte Claims enthalten Anwendungsdaten: scope, role, tenant_id, email. Halten Sie diese klein und nicht-sensitiv. Da ein Token bei jeder Anfrage mitgesendet wird, ist ein aufgeblähter Payload eine dauerhafte Belastung für Bandbreite und Latenz.
Es ist verlockend, das gesamte Profil des Benutzers in das Token zu packen, um einen Datenbank-Read zu vermeiden. Widerstehen Sie diesem Impuls. Claims veralten in dem Moment, in dem sich eine Rolle ändert, und Sie können ein Token, das ein Client bereits besitzt, nicht nachträglich ungültig machen. Packen Sie nur das hinein, was der Verifizierer wirklich benötigt, und rufen Sie den Rest bei Bedarf ab.
Token erstellen und verifizieren
In Node ist jose die moderne Wahl. Es basiert auf Promises, funktioniert in jeder Runtime, einschließlich Cloudflare Workers und Deno, und bietet eine kleine, präzise API. jsonwebtoken ist die ältere Library mit Callback-Struktur und ist in bestehendem Code nach wie vor weit verbreitet.
import { SignJWT } from "jose";
export async function issueAccessToken(userId: string, scope: string) {
return new SignJWT({ scope })
.setProtectedHeader({ alg: "HS256", typ: "JWT" })
.setSubject(userId)
.setIssuer("https://auth.example.com")
.setAudience("api.example.com")
.setIssuedAt()
.setExpirationTime("15m")
.setJti(crypto.randomUUID())
.sign(new TextEncoder().encode(process.env.JWT_SECRET));
}
Bei der Verifizierung entscheidet sich die Sicherheit. Ein Verifizierer muss die Signatur prüfen, den Algorithmus festlegen und exp, iss sowie aud validieren. Eine Library wird einen Token gerne dekodieren, ohne ihn zu verifizieren – und dieser dekodierte Payload ist dann eine vom Angreifer kontrollierte Eingabe.
import { jwtVerify, type JWTPayload } from "jose";
const secret = new TextEncoder().encode(process.env.JWT_SECRET);
export async function verifyAccessToken(token: string): Promise<JWTPayload> {
const { payload } = await jwtVerify(token, secret, {
algorithms: ["HS256"],
issuer: "https://auth.example.com",
audience: "api.example.com",
});
return payload;
}
Beachten Sie, dass jwtVerify exp und nbf automatisch erzwingt, aber iss und aud nur prüft, wenn Sie diese übergeben. Diese wegzulassen ist eine echte Sicherheitslücke: Ein für einen Staging-Service ausgestellter Token würde dann auch in der Produktion akzeptiert werden, ebenso wie ein Token, der für eine ganz andere Anwendung erstellt wurde.
Access- und Refresh-Token
Ein einzelnes, langlebiges Token ist zwar praktisch, aber gefährlich. Die Standardlösung ist ein Paar mit unterschiedlichen Laufzeiten und unterschiedlichen Zielgruppen (Audiences).
- Das access token ist kurzlebig, typischerweise 5 bis 15 Minuten. Es wird bei jedem API-Aufruf mitgesendet und ist das einzige Token, das der Resource Server jemals sieht.
- Das refresh token ist langlebig, von einigen Tagen bis hin zu Monaten. Es wird nur an den Authorization Server gesendet, um im Austausch ein neues access token zu erhalten.
Diese Aufteilung begrenzt den potenziellen Schaden. Wenn ein access token durchsickert, ist es innerhalb weniger Minuten wertlos. Das refresh token, welches wesentlich sensibler ist, wird niemals an Resource Server übertragen und kann rotiert oder widerrufen werden – hier liegt die eigentliche Kontrolle.
Refresh Token Rotation
Rotation bedeutet, dass bei jeder Aktualisierung ein neues Refresh Token ausgestellt und das alte ungültig gemacht wird. Wenn ein Angreifer ein Refresh Token stiehlt und verwendet, wird der legitime Client später ein bereits verwendetes Token vorlegen. Der Server kann diese Mehrfachverwendung erkennen und die gesamte Token-Familie widerrufen.
import { randomUUID } from "node:crypto";
export async function rotateRefreshToken(presented: string) {
const stored = await db.refreshToken.findUnique({ where: { token: presented } });
if (!stored || stored.revokedAt || stored.expiresAt < new Date()) {
if (stored) await revokeFamily(stored.familyId);
throw new Error("invalid_refresh_token");
}
await db.refreshToken.update({
where: { id: stored.id },
data: { revokedAt: new Date(), replacedBy: randomUUID() },
});
return issueTokenPair(stored.userId, stored.familyId);
}
Speichere Refresh Tokens gehasht, genau so, wie du Passwörter speichern würdest. Ein Datenbank-Leak sollte einem Angreifer keine funktionierenden Zugangsdaten liefern, denn ein Refresh Token ist im Grunde nichts anderes als ein Passwort, das das Login-Formular umgeht.
Wo man Tokens im Browser speichert
Es gibt keinen perfekten Ort, sondern nur Kompromisse zwischen Cross-Site Scripting und Cross-Site Request Forgery.
- localStorage kann von jedem Skript auf der Seite gelesen werden. Ein einziger XSS-Bug genügt, und der Angreifer exfiltriert jedes Token. Dies ist der Fehler, der immer wieder in Berichten über Datenlecks auftaucht.
- In-memory, also als Variable in einem Modul, ist sicher vor persistentem XSS, geht aber beim Aktualisieren der Seite verloren. Daher wird dies normalerweise mit einem Refresh Token in einem httpOnly Cookie kombiniert.
- Ein httpOnly, Secure, SameSite Cookie kann nicht von JavaScript gelesen werden, was den Diebstahl von Tokens via XSS neutralisiert. Dies führt jedoch CSRF wieder ein, was durch
SameSite=LaxoderStrictzusammen mit einem CSRF-Token abgeschwächt wird.
Für eine Browser-Anwendung ist der pragmatische Standard ein kurzlebiges Access Token im Speicher und ein rotierender Refresh Token in einem httpOnly Cookie, der auf den Refresh-Endpunkt beschränkt ist. Native und serverseitige Clients haben diese Einschränkung nicht und können Tokens in einem sicheren Speicher oder einfach im Arbeitsspeicher halten.
Der Trade-off der Statelessness und das Revocation-Problem
Das Hauptargument für JWTs ist die Statelessness. Jeder Server kann einen Token verifizieren, ohne auf einen gemeinsamen State zugreifen zu müssen, was eine hervorragende Skalierung über verschiedene Regionen hinweg ermöglicht und das horizontale Scaling trivial macht. Der Preis dafür ist, dass das Revocation (Widerrufen von Token) ausgesprochen schwierig ist. Ein signierter Token ist bis zu seinem Ablaufdatum gültig – völlig unabhängig davon, ob Sie den Benutzer inzwischen gelöscht, seine Rolle geändert oder ihn ausgeloggt haben. Es gibt keinen zentralen Datensatz, den man löschen könnte.
Sie können jedoch einen Teil der Kontrolle zurückgewinnen:
- Halten Sie Access Token kurz, sodass das Zeitfenster für das Revocation nur wenige Minuten statt Tage beträgt.
- Führen Sie eine Deny-List von
jti-Werten für seltene, sofortige Logouts, die bei jeder Anfrage geprüft wird. Dies führt den State wieder ein, daher sollte die Liste klein gehalten werden und Einträge automatisch ablaufen. - Fügen Sie einen pro Benutzer spezifischen
token_version-Claim hinzu und lehnen Sie Token ab, deren Version veraltet ist. Eine Passwortänderung oder eine Rollenanpassung erhöht diese Version.
Hier ist die ehrliche Zusammenfassung: JWTs tauschen ein einfaches Revocation gegen eine einfache Skalierung. Wenn Sie eine sofortige Sperrung an allen Stellen benötigen, könnten Session-Cookies mit einem Store im Hintergrund besser geeignet sein, wie in Session Auth beschrieben.
Algorithm Confusion und alg none
Zwei Angriffsvektoren sind so alt, dass sie bereits in Lehrbüchern stehen, finden aber immer noch Opfer.
Der erste ist alg: none. Ein Angreifer ändert den Header auf {"alg":"none"} und entfernt die Signatur. Ein naiver Verifizierer, der dem Header vertraut, akzeptiert das gefälschte Token. Der zweite ist die HS/RS-Confusion. Ein Service, der RS256-Tokens erwartet, wird dazu verleitet, ein HS256-Token zu akzeptieren, das mit dem RSA-Public-Key signiert wurde – welcher per Definition öffentlich zugänglich ist.
Beide haben die gleiche Lösung: Der Verifizierer legt den Algorithmus fest, nicht das Token.
// Good: the verifier decides.
await jwtVerify(token, secret, { algorithms: ["HS256"] });
// Bad: the token decides.
const { header } = decodeProtectedHeader(token);
await jwtVerify(token, secret, { algorithms: [header.alg] });
Lehnen Sie alg: none konsequent ab, leiten Sie den Key niemals aus einer nicht vertrauenswürdigen Quelle ab und behandeln Sie den Header als Daten, nicht als Anweisungen.
Scopes und Autorisierung
Die Authentifizierung beantwortet die Frage, wer jemand ist, und Scopes beantworten die Frage, was diese Person tun darf. Ein scope Claim ist eine durch Leerzeichen getrennte Liste von Berechtigungen, die von einer middleware geprüft wird, bevor ein Handler ausgeführt wird.
export function requireScope(required: string) {
return (req, res, next) => {
const granted = String(req.user.scope ?? "").split(" ");
if (!granted.includes(required)) {
return res.status(403).json({ error: "insufficient_scope" });
}
next();
};
}
Halten Sie Scopes grobmaschig und stabil und erzwingen Sie diese auf dem Server. Ein Token ohne den richtigen Scope muss mit einem 403-Fehler fehlschlagen, nicht mit 401: Der Aufrufer ist authentifiziert, aber nicht berechtigt. Für komplexere Zugriffsmodelle, die auf Rollen und Attributen basieren, lesen Sie mehr über RBAC.
JWT vs. opaque tokens
Ein JWT ist ein Bearer Token, das seine eigene Validierung mitführt. Ein opaque token hingegen ist eine zufällige Zeichenfolge ohne inhärente Bedeutung, sodass der Server diesen nachschlagen muss, um Informationen zu erhalten.
Opaque tokens haben Vorteile bei der Widerrufbarkeit (Revocation) und dem Datenschutz. Sie können eine Session sofort löschen, und falls ein Token durchsickert, gibt es keinerlei Informationen preis. Der Preis dafür ist ein Datenbank- oder Cache-Roundtrip bei jeder Anfrage. JWTs punkten bei der Skalierbarkeit und Unabhängigkeit. Services können sie lokal verifizieren und benötigen keinen gemeinsamen Speicher, allerdings auf Kosten eines Zeitfensters, in dem ein widerrufener Token noch gültig bleibt.
Viele Produktionssysteme setzen auf beides: ein JWT access token für die Geschwindigkeit und ein opaque refresh token für die Kontrolle. Dieser Hybrid-Ansatz ist das, was die meisten Identity Provider heute anbieten, und ist ein guter Standard, wenn Sie sich nicht entscheiden können.
Schlüsselrotation mit kid
Signaturschlüssel sollten nicht ewig gültig sein. Eine Rotation begrenzt den Schaden eines kompromittierten Schlüssels, und das Header-Feld kid sorgt dafür, dass die Rotation für Clients unsichtbar bleibt: Der Verifizierer liest kid, wählt den passenden Schlüssel aus und prüft die Signatur.
import { SignJWT, jwtVerify, createLocalJWKSet } from "jose";
const jwks = createLocalJWKSet({
keys: [{ kty: "oct", kid: "2026-09", k: process.env.JWT_SECRET }],
});
// The verifier resolves the key from the header's kid.
await jwtVerify(token, jwks, { algorithms: ["HS256"] });
Wenn Sie rotieren, veröffentlichen Sie den neuen Schlüssel neben dem alten, signieren Sie neue Tokens mit der neuen kid und verifizieren Sie den alten Schlüssel so lange weiter, bis jedes mit ihm signierte Token abgelaufen ist. Wenn Sie ihn zu früh entfernen, melden Sie alle aktiven Benutzer gleichzeitig ab. Veröffentlichen Sie bei asymmetrischen Schlüsseln ein JWKS-Dokument unter einer bekannten URL und lassen Sie es von den Resource Servern cachen.
Token-Lebensdauern in der Praxis
Die Ablaufzeit ist ein Balanceakt zwischen Sicherheit und Komfort. Es gibt keine universell richtige Antwort, aber die Struktur eines sinnvollen Standardwerts ist konsistent.
- Access tokens: 5 bis 15 Minuten. Kurz genug, damit ein Leak schnell wertlos wird, aber lang genug, damit nicht bei jeder Anfrage ein Refresh nötig ist.
- Refresh tokens: 7 bis 30 Tage, mit Rotation und einem Sliding Window. Langlebig genug, um Nutzer angemeldet zu lassen, aber kurz genug, damit ein vergessenes Token irgendwann abläuft.
- Absolute Session-Limit: 30 bis 90 Tage. Ein maximales Alter, nach dem sich der Nutzer erneut authentifizieren muss, unabhängig davon, wie oft er den Refresh-Prozess durchlaufen hat.
Wenn sich Ihre Nutzer darüber beschweren, dass sie ausgeloggt werden, liegt die Lösung in einem reibungsloseren Silent Refresh, nicht in einem längeren Access token. Ein 24-stündiges Access token ist ein vorprogrammierter Ausfall bei der Token-Widerrufung (Revocation).
Einen Token debuggen, ohne ihm zu vertrauen
Wenn eine Anfrage mit einem 401-Fehler fehlschlägt, möchten Sie sehen, welche Claims der Token enthält, ohne dabei die Verifizierung zu schwächen. Das Dekodieren ist sicher, solange Sie das Ergebnis als nicht vertrauenswürdige Daten behandeln.
import { decodeJwt, decodeProtectedHeader } from "jose";
const header = decodeProtectedHeader(token);
const claims = decodeJwt(token);
console.log({ alg: header.alg, kid: header.kid });
console.log({
sub: claims.sub,
iss: claims.iss,
aud: claims.aud,
exp: new Date((claims.exp ?? 0) * 1000).toISOString(),
expired: (claims.exp ?? 0) * 1000 < Date.now(),
});
Die beiden häufigsten Fehler, auf die Sie stoßen werden, sind ein aud-Mismatch nach einer Umbenennung eines Dienstes und ein iss-Mismatch nach einem Wechsel zwischen Umgebungen. Beides sind Konfigurationsprobleme, die unsichtbar bleiben, bis Sie die Claims ausgeben.
Tokens testen
Du solltest in der Lage sein, eine authentifizierte Route zu testen, ohne einen Identity Provider bereitstellen zu müssen. Da ein JWT lediglich ein signierter String ist, genügt ein Test-Helper, der einen Token mit demselben Test-Secret signiert.
import { SignJWT } from "jose";
import request from "supertest";
import app from "../app.js";
const secret = new TextEncoder().encode("test-secret");
async function tokenFor(scope = "read:posts") {
return new SignJWT({ scope })
.setProtectedHeader({ alg: "HS256" })
.setSubject("user_1")
.setIssuer("https://auth.example.com")
.setAudience("api.example.com")
.setExpirationTime("5m")
.sign(secret);
}
test("rejects a request without a token", async () => {
await request(app).get("/posts").expect(401);
});
test("accepts a request with a valid token", async () => {
const token = await tokenFor();
await request(app)
.get("/posts")
.set("authorization", `Bearer ${token}`)
.expect(200);
});
Teste zudem die Negativfälle: einen abgelaufenen Token, einen Token mit dem falschen Audience und einen Token, der mit einem anderen Key signiert wurde. Genau diese Prüfungen schützen deine Anwendung, daher verdienen sie ebenso viel Testabdeckung wie der Happy Path.
Best Practices
- Setzen Sie immer
exp; halten Sie die Gültigkeit von Access Tokens auf 15 Minuten oder weniger begrenzt. - Pinnen Sie den Algorithmus auf dem Verifier und lehnen Sie
alg: noneab. - Validieren Sie
iss,aud,expundnbf; vertrauen Sie niemals einem Claim, den Sie nicht geprüft haben. - Halten Sie Secrets und private Keys aus der Versionsverwaltung fern und laden Sie diese aus einem Secret Manager.
- Speichern Sie Refresh Tokens gehasht und rotieren Sie diese bei jeder Verwendung.
- Halten Sie Claims klein und nicht-sensitiv; der Payload ist lesbar.
- Bevorzugen Sie in Browsern httpOnly Cookies oder den Speicher (Memory) gegenüber dem localStorage.
- Planen Sie den Widerruf (Revocation) durch kurze Laufzeiten, eine
jtiDeny-List oder eine Token-Version ein. - Verwenden Sie
josefür neuen Code; es ist Promise-basiert und über verschiedene Runtimes hinweg portabel.
Häufige Fehler
- Davon ausgehen, dass der Payload verschlüsselt ist, nur weil er wie Zeichensalat aussieht.
- Claims mit
decodeauslesen und diese als verifiziert betrachten. - Den
alg-Header des Tokens entscheiden lassen, welcher Verifizierungsalgorithmus genutzt wird. - Einen Token akzeptieren, ohne
audzu prüfen, sodass Staging-Tokens auch in der Production funktionieren. - Ein schwaches oder gemeinsam genutztes Secret verwenden oder dieses im Repository committen.
- Die Ablaufzeit auf 30 Tage setzen, weil das Refreshing nervig ist.
- Tokens im localStorage speichern und glauben, damit fertig zu sein.
- Eine Rolle in den Token schreiben und diese nicht invalidieren, wenn sich die Rolle ändert.
- Einen 401- und einen 403-Fehler als denselben Fehler behandeln.
Wie geht es weiter?
JWTs sind nur ein Werkzeug in einem größeren Toolkit für die Identitätsverwaltung. Der OAuth 2.0-Guide zeigt, wie Token tatsächlich über delegierte Autorisierung bezogen werden, Session Auth behandelt die cookie-basierte Alternative für Fälle, in denen ein sofortiger Widerruf (Revocation) erforderlich ist, und API Keys erklärt langlebige Anmeldedaten für Machine-Clients. Wenn Sie sehen möchten, wie dieser Verifizierungscode in einem echten Server implementiert wird, lesen Sie den Abschnitt zu Node.js.