Was OAuth 2.0 ist – und was nicht
OAuth 2.0 ist ein Authorization Framework. Es ermöglicht einem Nutzer, einer Drittanbieter-Anwendung begrenzten Zugriff auf seine Ressourcen zu gewähren, ohne sein Passwort teilen zu müssen. Das Ergebnis eines erfolgreichen Flows ist ein Access Token. Dieses Token beschreibt, was der Client tun darf, aber nicht zwangsläufig, wer der Nutzer ist.
Diese Unterscheidung führt immer wieder zu Verwirrungen. „Sign in with Google“ ist OAuth 2.0 plus OpenID Connect. Der OAuth-Teil beschafft den Zugriff auf die Google APIs; der OpenID Connect-Teil liefert ein ID Token zurück, das den Nutzer tatsächlich identifiziert. Wenn Sie nur OAuth implementieren und das Access Token als Identitätsnachweis behandeln, haben Sie einen delegierten Zugriff implementiert und diesen fälschlicherweise als Authentifizierung bezeichnet – ein Kategorienfehler mit entsprechenden Sicherheitsrisiken.
Das Protokoll wurde für ein ganz spezifisches Problem entwickelt: Eine Seite für Fotodrucke soll Fotos von einem Storage-Provider lesen können, ohne jemals das Passwort für den Storage-Account zu sehen. Behalten Sie diese ursprüngliche Intention im Hinterkopf, dann ergeben die Design-Entscheidungen einen Sinn.
OpenID Connect: Identität als zusätzliche Schicht
OpenID Connect ist eine schlanke Identitätsschicht über OAuth 2.0. Sie fügt den openid Scope, einen standardisierten userinfo Endpoint und vor allem ein ID Token hinzu – ein JWT, dessen Claims das Authentifizierungsereignis beschreiben.
{
"iss": "https://accounts.example.com",
"sub": "110169484474386276334",
"aud": "web-app",
"exp": 1760000000,
"iat": 1759999100,
"email": "[email protected]",
"email_verified": true,
"nonce": "n-0S6_WzA2Mj"
}
Das ID Token ist für den Client gedacht, nicht für die API. Senden Sie es niemals als Access Token an einen Resource Server. Verifizieren Sie die Signatur, iss, aud, exp und nonce, bevor Sie dem Token vertrauen, und verwenden Sie sub anstelle der E-Mail-Adresse als stabilen Benutzeridentifikator. E-Mail-Adressen ändern sich oder werden neu zugewiesen; der Subject bleibt über die gesamte Lebensdauer des Accounts stabil.
Die vier Rollen
OAuth definiert vier Teilnehmer. Wenn man diese präzise unterscheidet, wird der Rest des Protokolls fast von selbst klar.
- Resource owner — der Nutzer, dem die Daten gehören und der den Zugriff gewährt.
- Client — die Anwendung, die den Zugriff anfordert, zum Beispiel deine Web-App.
- Authorization server — stellt Tokens aus, nachdem der Nutzer authentifiziert wurde und seine Zustimmung gegeben hat.
- Resource server — die API, die das Access Token akzeptiert und die Daten zurückgibt.
Deine Web-App ist der Client. Google ist der Authorization server. Die APIs von Google sind der Resource server. Der Nutzer ist der Resource owner. Ein einziger Provider übernimmt oft beide Server-Rollen, weshalb die Unterscheidung theoretisch wirken kann, bis man selbst ein solches System baut.
Grant Types
Ein Grant Type ist das „Rezept“, das ein Client verwendet, um ein Token zu erhalten. Heutzutage sind vier davon relevant.
- Authorization Code + PKCE — der Standard für Web-, Mobile- und Single-Page-Apps. Der Benutzer authentifiziert sich am Authorization Server, und der Client tauscht einen kurzlebigen Code gegen Tokens ein.
- Client Credentials — für Machine-to-Machine-Kommunikation. Es ist kein Benutzer involviert; der Client authentifiziert sich mit seinen eigenen Credentials.
- Device Code — für Geräte mit eingeschränkter Eingabe, wie zum Beispiel Fernseher und CLI-Tools.
- Refresh Token — kein Weg zum Einloggen, sondern die Standardmethode, um ein Access Token ohne erneuten Redirect zu erneuern.
Zwei Grants sind praktisch hinfällig. Der implicit Flow gab Tokens direkt im URL-Fragment zurück, wodurch sie in der History und über Referrer exponiert wurden. Der password Grant verlangte vom Client, das Passwort des Benutzers zu verarbeiten, was den eigentlichen Zweck von OAuth zunichtemacht. OAuth 2.1 entfernt beide, und kein neues System sollte sie mehr verwenden.
Authorization Code + PKCE
Dies ist der Flow, den man beherrschen sollte. Der Client leitet den Benutzer mit einer gehashten Challenge an den Authorization Server weiter, der Benutzer stimmt zu, der Server leitet mit einem einmaligen Code zurück und der Client tauscht diesen Code zusammen mit dem ursprünglichen Verifier gegen Tokens ein.
Der Code ist ohne den Verifier nutzlos, sodass ein Angreifer, der den Redirect abfängt, den Austausch nicht abschließen kann. Genau das macht PKCE sicher – selbst für Public Clients wie mobile Apps und Single-Page Apps, die keinerlei Secrets sicher speichern können.
Der Flow besteht aus zwei Browser-Redirects und einer Back-Channel-Anfrage. Die Redirects sind sichtbar und können manipuliert werden; der Austausch hingegen ist ein direkter Server-to-Server POST, den ein Angreifer nicht beobachten kann. Das gesamte Design basiert darauf, das geheime Material über den Back Channel zu übertragen.
Die Redirect URI und der State
Die redirect URI ist die Adresse, an die der Authorization Server den Benutzer zurückschickt. Sie muss exakt registriert sein und exakt übereinstimmen. Eine zu lockere Prüfung ist die Ursache für Open-Redirect-Schwachstellen, durch die Authorization Codes an vom Angreifer kontrollierte Hosts geleakt werden können. Akzeptieren Sie niemals eine redirect URI aus einem Query-Parameter und erlauben Sie keine Wildcard-Subdomains.
Der state-Parameter ist ein opaker Wert, den der Client generiert und überprüft, wenn der Callback zurückkehrt. Er schützt den Callback-Endpunkt vor CSRF. Ein Angreifer, der ein Opfer dazu bringt, einen Flow mit dem Code des Angreifers abzuschließen, wird die State-Prüfung nicht bestehen.
const state = randomBytes(16).toString("base64url");
session.oauthState = state;
// later, in the callback:
if (query.state !== session.oauthState) {
throw new Error("state_mismatch");
}
Fügen Sie für OIDC einen nonce hinzu und verifizieren Sie diesen innerhalb des ID-Tokens. Der State schützt den Callback des Clients vor CSRF; der nonce bindet das ID-Token an diese spezifische Anfrage und verhindert Replay-Angriffe.
PKCE im Detail
PKCE (Proof Key for Code Exchange) ist in RFC 7636 definiert und mittlerweile für Public Clients obligatorisch. Es basiert auf drei Werten: Der Client generiert einen zufälligen code_verifier, leitet daraus einen code_challenge als SHA-256-Hash ab, sendet die Challenge mit dem Authorize-Request und den Verifier mit dem Token-Request. Der Server hasht anschließend den Verifier und vergleicht die Ergebnisse.
import { randomBytes, createHash } from "node:crypto";
const verifier = randomBytes(32).toString("base64url");
const challenge = createHash("sha256").update(verifier).digest("base64url");
Verwenden Sie immer die S256-Methode. Die plain-Methode existiert nur aus Kompatibilitätsgründen und macht den Zweck von PKCE zunichte, da ein Angreifer, der die Challenge sieht, gleichzeitig auch den Verifier sieht. Speichern Sie den Verifier in der Session des Benutzers, damit der Callback ihn finden kann, und löschen Sie ihn nach einmaliger Verwendung.
Den Authorize-Request erstellen
Der Authorize-Request ist ein Browser-Redirect und daher ein GET-Request mit Query-Parametern. Der Benutzer sieht den Consent-Screen des Providers und nicht Ihre Anwendung.
export function buildAuthorizeUrl(state: string, challenge: string) {
const url = new URL("https://auth.example.com/authorize");
url.search = new URLSearchParams({
response_type: "code",
client_id: "web-app",
redirect_uri: "https://app.example.com/callback",
scope: "openid email profile offline_access",
state,
code_challenge: challenge,
code_challenge_method: "S256",
}).toString();
return url.toString();
}
response_type=code wählt den Authorization Code Flow aus. Der Scope openid macht den Request zu einem OIDC-Request. offline_access ist die gängige Konvention, um einen Refresh Token anzufordern; einige Provider schalten diesen hinter eine zusätzliche Bestätigung (Consent Prompt).
Token-Austausch
Der Callback liefert code und state. Nach der Überprüfung des State sendet der Client den Code per POST an den Token-Endpunkt. Dies ist ein Back-Channel-Aufruf von Ihrem Server, kein Browser-Redirect.
export async function exchangeCode(code: string, verifier: string) {
const res = await fetch("https://auth.example.com/token", {
method: "POST",
headers: { "content-type": "application/x-www-form-urlencoded" },
body: new URLSearchParams({
grant_type: "authorization_code",
code,
redirect_uri: "https://app.example.com/callback",
client_id: "web-app",
code_verifier: verifier,
}),
});
if (!res.ok) throw new Error("token_exchange_failed");
return res.json();
}
Die Antwort enthält access_token, token_type, expires_in, normalerweise refresh_token und bei OIDC ein id_token. Ein Confidential Client, also einer, der ein Secret sicher speichern kann, authentifiziert sich bei dieser Anfrage zudem mittels client_secret oder, noch besser, über eine Private-Key-Assertion. Ein Public Client verlässt sich ausschließlich auf PKCE.
Access-, Refresh- und ID-Tokens
Diese drei Tokens haben unterschiedliche Aufgaben, und eine Verwechslung führt oft zu subtilen Bugs.
- Access token — wird dem Resource Server präsentiert. Es ist häufig ein JWT, aber die Spezifikation verlangt lediglich, dass es für den Client opak ist. Es kann sich also auch um einen zufälligen String handeln, den der Server nachschlägt.
- Refresh token — wird ausschließlich dem Authorization Server präsentiert, um ein neues Access token zu erhalten. Es ist langlebig und hochsensibel.
- ID token — ein OIDC JWT, das dem Client mitteilt, wer sich gerade angemeldet hat. Es wird niemals an eine API gesendet.
Behandeln Sie das Access token als Bearer-Credential: Jeder, der es besitzt, kann es verwenden. Halten Sie die Lebensdauer kurz, fordern Sie nur die minimal benötigten Scopes an und überlassen Sie die langfristige Beziehung dem Refresh token. Das Token-Format selbst wird im JWT-Guide behandelt.
Scopes und Consent
Scopes drücken aus, wofür der Client anfragt. Der Authorization Server zeigt diese dem Benutzer in einem Consent-Screen an und kodiert die gewährte Teilmenge in das Access Token.
Fordern Sie nur das Minimum an. Eine Kalender-App, die vollen Zugriff auf das gesamte Postfach verlangt, wird Nutzer abschrecken und den potenziellen Schaden bei einer Sicherheitslücke (Blast Radius) vergrößern. Provider veröffentlichen zudem reservierte Scopes: openid ist für OIDC erforderlich, und offline_access steuert in der Regel die Refresh Tokens.
Scopes sind keine Rollen. Ein Scope beschreibt eine Berechtigung, die der Client für diesen Grant angefordert hat; eine Rolle beschreibt, wer der Benutzer innerhalb Ihres Systems ist. Bilden Sie diese auf Ihrem Server aufeinander ab und gehen Sie niemals davon aus, dass die Scopes eines Providers etwas über Ihr eigenes Autorisierungsmodell aussagen. Für diesen Aspekt des Problems lesen Sie bitte unter RBAC.
Den Resource Server aufrufen
Sobald ein Access Token vorliegt, wird dieser bei API-Aufrufen im Authorization Header mittels des Bearer-Schemas übermittelt.
const res = await fetch("https://api.example.com/me", {
headers: { authorization: `Bearer ${accessToken}` },
});
Der Resource Server validiert den Token – entweder durch die lokale Verifizierung eines JWT oder per Introspection –, prüft den Scope und gibt die Daten zurück. Er sieht niemals den Refresh Token oder den ID Token und sollte diese ablehnen, falls sie dennoch übermittelt werden.
Introspection und Revocation
Nicht jeder Access Token ist ein JWT. Wenn es sich um einen opaque Token handelt, fragt der Resource Server den Authorization Server mittels Token Introspection (definiert durch RFC 7662) ab, ob dieser noch gültig ist.
POST /introspect HTTP/1.1
Host: auth.example.com
Content-Type: application/x-www-form-urlencoded
Authorization: Basic <client credentials>
token=2YotnFZFEjr1zCsicMWpAA
Die Introspection gibt active sowie den Scope, den Subject und das Ablaufdatum zurück. Diese Antwort ist maßgeblich, erfordert jedoch einen Netzwerkaufruf; cachen Sie das Ergebnis daher für einige Sekunden.
Revocation (definiert durch RFC 7009) ermöglicht es einem Client, den Authorization Server anzuweisen, einen Token ungültig zu machen – in der Regel beim Logout.
await fetch("https://auth.example.com/revoke", {
method: "POST",
headers: { "content-type": "application/x-www-form-urlencoded" },
body: new URLSearchParams({ token: refreshToken, client_id: "web-app" }),
});
Widerrufen Sie Refresh Tokens beim Logout konsequent und bedenken Sie, dass das Widerrufen eines Refresh Tokens nicht automatisch bereits ausgestellte Access Tokens ungültig macht. Kurze Lebensdauern für Access Tokens sorgen dafür, dass die Revocation unmittelbar wirkt.
Machine-to-machine: client credentials
Wenn kein Benutzer involviert ist, agiert der Client als er selbst. Er authentifiziert sich am Token-Endpoint und erhält ein Access Token, das auf seine eigenen Berechtigungen beschränkt ist.
const res = await fetch("https://auth.example.com/token", {
method: "POST",
headers: {
"content-type": "application/x-www-form-urlencoded",
authorization: `Basic ${btoa(`${clientId}:${clientSecret}`)}`,
},
body: new URLSearchParams({
grant_type: "client_credentials",
scope: "reports:read",
}),
});
Es gibt keinen Consent-Screen und kein Refresh Token; der Service fordert einfach ein neues Token an, wenn das alte abläuft. Bevorzugen Sie die private-key JWT client authentication gegenüber einem shared secret, sofern der Provider dies unterstützt, und rotieren Sie Secrets in regelmäßigen Abständen. Dies ist dieselbe Nische, die auch langlebige API keys besetzen, jedoch mit standardisiertem Ablaufdatum und Scoping, wie in API Keys beschrieben.
Wann man OAuth nicht verwenden sollte
OAuth dient dazu, den Zugriff an eine dritte Partei zu delegieren. Wenn Ihre eigene Web-App ihre eigenen Benutzer gegenüber ihrem eigenen Backend authentifiziert, benötigen Sie kein OAuth. Ein Session-Cookie oder ein First-Party JWT, den Sie selbst ausstellen, ist einfacher und leichter abzusichern. Einen Authorization Server zwischen Ihr Login-Formular und Ihre Datenbank zu schalten, bringt Komplexität, aber keine zusätzliche Sicherheit.
Greifen Sie zu OAuth, wenn Sie einen externen Provider integrieren, selbst als Provider für Drittanbieter-Clients fungieren oder einen Standard für den Machine-to-Machine-Zugriff benötigen. Beginnen Sie ansonsten mit Session Auth und fügen Sie OAuth erst hinzu, wenn ein echter Delegationsbedarf entsteht. Da jeder hier beschriebene Flow über Redirects und Header läuft, ist der HTTP-Guide eine nützliche Ergänzung.
Häufige Fallstricke
- Implicit flow — Tokens im URL-Fragment können über den Verlauf, Logs und Referrer durchsickern. Verwenden Sie stattdessen Authorization Code mit PKCE.
- Tokens in localStorage — Ein XSS-Bug führt hier direkt zur Übernahme des Benutzerkontos. Speichern Sie Tokens in httpOnly cookies oder server-seitigen Sessions.
- Open redirects — Eine zu lockere Prüfung der Redirect-URI ermöglicht es Angreifern, Codes zu stehlen. Die registrierte URI muss exakt übereinstimmen.
- Verzicht auf state — Ohne diesen Parameter ist der Callback anfällig für CSRF.
- Zu weit gefasste Scopes — Wenn alles angefordert wird, verliert die Zustimmung (Consent) ihre Bedeutung und Datenlecks werden schwerwiegender.
- Langlebige Access Tokens — Diese können nicht schnell widerrufen werden. Halten Sie die Laufzeit kurz und rotieren Sie die Refresh Tokens.
- Verwendung des ID tokens als API-Credential — Dieses ist für den Client gedacht, nicht für den Resource Server.
Den richtigen Flow auswählen
Die meisten Entscheidungen bei der Integration lassen sich auf zwei Fragen reduzieren: Gibt es einen Benutzer und kann der Client ein Geheimnis bewahren?
- Ein Benutzer ist vorhanden, der Client ist öffentlich (SPA, mobile App, Desktop): Authorization Code mit PKCE.
- Ein Benutzer ist vorhanden, der Client ist vertraulich (server-rendered Web App): Authorization Code mit PKCE plus Client-Authentifizierung.
- Kein Benutzer, der Client ist ein Service (Cronjob, Microservice): Client Credentials.
- Das Gerät hat keinen Browser oder keine Tastatur (TV, CLI): Device Code.
Alles andere ist veraltet. Wenn ein Provider nur den Implicit Flow dokumentiert, sollte dies als Warnsignal gewertet werden; prüfen Sie in diesem Fall, ob PKCE verfügbar ist.
Das Backend-for-Frontend-Pattern
Der sicherste Ort für die Speicherung von Tokens ist ein Server, den Sie selbst kontrollieren. Das Backend-for-Frontend-Pattern setzt einen schlanken Server zwischen den Browser und den Authorization-Server: Der Browser erhält ein Session-Cookie, während der Server die Access- und Refresh-Tokens verwaltet.
app.get("/callback", async (req, res) => {
if (req.query.state !== req.session.oauthState) {
return res.status(400).json({ error: "state_mismatch" });
}
const tokens = await exchangeCode(
String(req.query.code),
req.session.codeVerifier,
);
req.session.tokens = tokens;
delete req.session.oauthState;
delete req.session.codeVerifier;
res.redirect("/dashboard");
});
Da der Browser niemals ein Token sieht, können diese nicht per XSS gestohlen werden, und der Server kann die Tokens im Hintergrund (silent) aktualisieren. Der Kompromiss besteht in einem zusätzlichen Netzwerk-Hop und einem zu betreibenden Server – was in der Regel günstiger ist als der Vorfall, den man dadurch vermeidet.
Native und mobile Clients
Native Apps können kein Client Secret sicher speichern, weshalb PKCE obligatorisch ist. Zudem gibt es ein Problem mit dem Redirect: Ein benutzerdefiniertes Scheme wie myapp://callback kann von einer bösartigen App beansprucht werden. Die moderne Lösung ist ein Tab im Systembrowser – entweder über die Authentication Session API der Plattform oder einen eingebetteten Browser, der Cookies mit dem System teilt.
Verwenden Sie niemals ein eingebettetes WebView für OAuth. Die App könnte das Passwort des Nutzers auslesen, was die Trust Boundary verletzt, die das gesamte Protokoll schützen soll. Öffnen Sie den Systembrowser, empfangen Sie den Callback und speichern Sie die Tokens im Secure Storage der Plattform.
Einen eigenen Authorization Server betreiben
Sie müssen nicht selbst einen bauen. Etablierte Server wie Keycloak, Ory Hydra und Cloud-Identity-Provider implementieren das Protokoll, Consent-Screens, das Key-Management und die Token-Speicherung für Sie. Die Entwicklung eines eigenen Servers ist ein mehrmonatiges Projekt, bei dem jeder Fehler sicherheitskritisch ist.
Falls Sie dennoch einen eigenen betreiben, gehören zu den Mindestanforderungen: exaktes Matching der Redirect-URIs, die Erzwingung von PKCE, kurze Lebensdauern für Access-Token, Refresh-Token-Rotation mit Reuse-Detection, ein JWKS-Endpoint sowie Revocation. Wenn Sie auch nur einen dieser Punkte vernachlässigen, haben Sie eine Sicherheitslücke implementiert und kein Feature.
Eine OAuth-Integration testen
End-to-End-Tests für OAuth sind langsam und fehleranfällig, da sie von einem echten Provider und einem echten Browser abhängen. Testen Sie stattdessen in Schichten.
- Unit-Tests für die URL-Konstruktion, die PKCE-Ableitung und den State-Vergleich als reine Funktionen.
- Integrationstests für den Token-Austausch gegen einen Mock-Authorization-Server, der vordefinierte Tokens zurückgibt.
- Behalten Sie einen Smoke-Test gegen den echten Provider bei, markieren Sie diesen jedoch so, dass er nicht bei jedem Commit ausgeführt wird.
test("builds an authorize URL with PKCE", () => {
const url = new URL(buildAuthorizeUrl("state-1", "challenge-1"));
expect(url.searchParams.get("response_type")).toBe("code");
expect(url.searchParams.get("code_challenge_method")).toBe("S256");
expect(url.searchParams.get("state")).toBe("state-1");
});
Im Callback verbergen sich oft die meisten Bugs. Testen Sie daher die Fehlerpfade explizit: Ein nicht übereinstimmender State, ein bereits verwendeter Code und ein abgelaufener Token sollten jeweils einen klaren Fehler auslösen, anstatt eine halb authentifizierte Session zu erzeugen.
Logout und Single Sign-On
Das Ausloggen aus Ihrer Anwendung ist nicht dasselbe wie das Ausloggen beim Provider. Ein vollständiger Logout umfasst drei Schritte: Er zerstört die lokale Session, widerruft den Refresh Token am Authorization Server und beendet bei Single Sign-On die Provider-Session, damit der nächste Login diese nicht stillschweigend wiederverwendet.
app.post("/logout", async (req, res) => {
if (req.session.tokens?.refresh_token) {
await revoke(req.session.tokens.refresh_token);
}
req.session.destroy(() => res.redirect("/"));
});
Single Sign-On ergibt sich aus demselben Mechanismus: Sobald ein Benutzer eine Session beim Provider hat, erhalten nachfolgende Clients einen Code, ohne dass das Passwort erneut eingegeben werden muss. Das ist bequem, und es ist auch der Grund, warum das Ausloggen an gemeinsam genutzten Computern wichtiger ist, als viele erwarten.
Refresh Token Rotation und Reuse Detection
OAuth schreibt nicht vor, dass Refresh Tokens nur einmal verwendet werden dürfen, aber die sichersten Implementierungen setzen auf Rotation. Jeder Refresh-Vorgang liefert ein neues Refresh Token zurück und invalidiert das vorherige. Wenn ein altes Token erneut präsentiert wird, erkennt der Server, dass es gestohlen wurde, und widerruft die gesamte Token-Familie.
export async function refresh(grant: { refresh_token: string; client_id: string }) {
const stored = await db.refreshToken.findByHash(hash(grant.refresh_token));
if (!stored || stored.revoked) {
if (stored) await revokeFamily(stored.familyId);
throw new Error("invalid_grant");
}
await db.refreshToken.revoke(stored.id);
return issueTokens(stored.userId, stored.familyId);
}
Die Reuse Detection ist hierbei der entscheidende Vorteil: Ein gestohlenes Refresh Token wird so zu einer Stolperfalle statt zu einer permanenten Hintertür. Kombinieren Sie dies mit einem Sliding Expiry, sodass aktive Nutzer angemeldet bleiben, während ein verlassenes Token schließlich abläuft.
Best Practices
- Verwenden Sie Authorization Code mit PKCE für jeden benutzerseitigen Client, einschließlich SPAs und mobile Apps.
- Nutzen Sie Client Credentials für Machine-to-Machine-Kommunikation, idealerweise mit Private-Key-Authentifizierung.
- Registrieren Sie exakte Redirect URIs und lehnen Sie jede Anfrage ab, die nicht zeichengenau übereinstimmt.
- Senden und verifizieren Sie immer
state; fügen Sie für OIDC einennoncehinzu und verifizieren Sie diesen. - Fordern Sie nur die minimal notwendigen Scopes an und behandeln Sie den Consent-Screen als bedeutsames Element.
- Halten Sie Access Tokens kurzlebig, rotieren Sie Refresh Tokens und widerrufen Sie diese beim Logout.
- Verifizieren Sie die Signatur des ID Tokens sowie
iss,aud,expundnonce, bevor Sie diesem vertrauen. - Speichern Sie Client Secrets und Private Keys in einem Secret Manager, niemals im Frontend.
- Cachen Sie Introspection nur kurzzeitig und setzen Sie für einen zeitnahen Widerruf auf kurze Laufzeiten.
Häufige Fehler
- OAuth als Authentifizierung behandeln, ohne OpenID Connect zu nutzen.
- Den Implicit Flow implementieren, nur weil er einen Redirect weniger benötigt.
- Access Tokens im localStorage speichern und an jeden Origin senden.
- Das Client Secret in einer Single-Page App hinterlegen, wo es für jeden lesbar ist.
- Jede beliebige Redirect URI oder eine per Query-Parameter übergebene URI akzeptieren.
- Vergessen,
statebeim Callback zu validieren. - Jeden verfügbaren Scope anfordern und die Liste nie wieder zu überarbeiten.
- Davon ausgehen, dass das Widerrufen eines Refresh Tokens sofort alle Access Tokens ungültig macht.
- Das ID Token als Bearer Token für die eigene API verwenden.
Wie geht es weiter?
OAuth ist die Methode, mit der Tokens beschafft werden; JWT erklärt, wie diese aufgebaut und verifiziert werden. Wenn es sich bei deiner App um eine First-Party-Anwendung handelt und du eine sofortige Widerrufbarkeit (Revocation) benötigst, ist Session Auth der einfachere Startpunkt. Für Machine-Clients, bei denen kein Benutzer involviert ist, bietet API Keys die langlebige Alternative. Und da jeder dieser Flows über das Netzwerk läuft, lohnt sich eine Auffrischung zum Thema HTTP.