OAuth 2.1 und OIDC verstehen: Flows, Token-Validierung, Fehlerbilder
OAuth ist Delegation, keine Authentifizierung. Aus genau dieser Verwechslung entstehen die meisten Identitätsfehler. Hier sind das mentale Modell, die relevanten Flows und die Validierungs-Checkliste, die in der Praxis standhalten.
Von Innovation T Team
OAuth ist ein Delegationsprotokoll, kein Authentifizierungsprotokoll. Dieses eine Missverständnis steckt hinter der Hälfte aller Identitätsfehler, die wir in Sicherheitsaudits finden. Wenn Ihr Team Login-Buttons, API-Tokens oder Machine-to-Machine-Dienste ausliefert, ersparen Ihnen die nächsten zehn Minuten Lektüre einen handfesten Sicherheitsvorfall.
Das falsche mentale Modell verlernen
OAuth 2.x beantwortet genau eine Frage: Darf diese Anwendung diese API aufrufen, gegebenenfalls im Auftrag eines Benutzers. Über die Identität dieses Benutzers sagt es nichts Belastbares aus. OpenID Connect (OIDC) ist die Identitätsschicht darüber: Es ergänzt ein ID Token, einen UserInfo-Endpunkt und strenge Regeln dafür, wie ein Client erfährt, dass ein Authentifizierungsereignis tatsächlich stattgefunden hat.
Diese Unterscheidung ist keine akademische Fußnote. Wenn Ihr Backend "ich habe ein Access Token erhalten" als "dieser Benutzer ist authentifiziert" interpretiert, kann jede Anwendung, die legitim ein Token für diesen Benutzer erhalten hat, es gegen Ihre API wiederverwenden und dessen Identität annehmen. Genau dieses Replay-Problem mit Access Tokens ist der Grund, warum OIDC überhaupt existiert. Delegation und Authentifizierung sind unterschiedliche Aussagen, und sie brauchen unterschiedliche Tokens.
Diesen Satz sollten Sie sich an die Wand heften: OAuth beschreibt, was eine App tun darf. OIDC beschreibt, wer der Benutzer ist.
Was OAuth 2.1 tatsächlich ändert
OAuth 2.1 ist formal noch ein IETF-Draft, sollte aber ab sofort als Baseline gelten. Es ist OAuth 2.0 mit einem Jahrzehnt eingearbeiteter Sicherheitserkenntnisse, die zuvor größtenteils in RFC 9700 formalisiert wurden, der OAuth Security Best Current Practice. Wer heute nach 2.1 baut, setzt schlicht 2.0 korrekt um. Mit Hype hat das nichts zu tun, mit Sorgfaltspflicht sehr viel.
Die konkreten Änderungen:
- Der Implicit Grant ist tot. Tokens im URL-Fragment sind über Browser-Verlauf, Referrer-Header und protokollierende Proxies geleakt. Das ließ sich nicht reparieren, also wurde der Flow gestrichen.
- Der Resource Owner Password Grant ist tot. Jeder Flow, der Benutzern beibringt, ihr Passwort in eine Drittanwendung einzutippen, ist ein Phishing-Trainingsprogramm.
- PKCE ist für jeden Authorization Code Flow verpflichtend, auch für Confidential Clients. Es unterbindet das Abfangen von Authorization Codes und liefert CSRF-Schutz gleich mit.
- Redirect URIs müssen exakt übereinstimmen. Keine Wildcards, kein Präfix-Matching, kein "alles unterhalb dieser Subdomain".
- Refresh Tokens für Public Clients müssen einmalig verwendbar sein (Rotation) oder sender-constrained.
- Bearer Tokens in Query-Strings sind verboten. Sie landen für immer in Access-Logs.
Verstößt Ihr Identity Provider oder Ihre eigene Implementierung gegen einen dieser Punkte, haben Sie damit Ihr Remediation-Backlog, bereits nach Priorität sortiert.
Die Bausteine, präzise benannt
Vier Rollen:
- Resource Owner: der Mensch, dem die Daten gehören.
- Client: die Anwendung, die Zugriff anfordert (SPA, Mobile App, Backend-Dienst).
- Authorization Server (AS): stellt Tokens aus, nachdem er den Benutzer authentifiziert und die Einwilligung protokolliert hat. Keycloak, Auth0, Entra ID, Cognito, Zitadel.
- Resource Server (RS): Ihre API, die Access Tokens entgegennimmt und validiert.
Drei Tokens mit sehr unterschiedlichen Aufgaben:
- Access Token: ein Berechtigungsnachweis für den Resource Server. Kurzlebig. Der Client sollte es als opaken String behandeln, auch wenn es zufällig ein JWT ist.
- Refresh Token: ein langlebiger Nachweis, den der Client gegen neue Access Tokens eintauscht, ohne den Benutzer zu behelligen. Das wertvollste Diebesgut für einen Angreifer.
- ID Token (nur OIDC): ein JWT, adressiert an den Client, nicht an irgendeine API. Es bestätigt: "Dieser Benutzer hat sich zu diesem Zeitpunkt mit dieser Methode authentifiziert." Seine Audience ist Ihre client_id.
Zwei Regeln verhindern ganze Fehlerklassen:
- ID Tokens überqueren niemals eine API-Grenze. Der Client konsumiert sie, danach ist ihre Aufgabe erledigt.
- Clients treffen niemals Entscheidungen durch das Parsen von Access Tokens. Der Inhalt des Tokens ist ein Vertrag zwischen AS und RS.
Die Flows, die 2026 zählen
Sie brauchen vier. Alles andere ist Altlast.
Authorization Code mit PKCE
Der Standard für alles Interaktive: Web-Anwendungen, SPAs, Mobile. Der Client erzeugt ein zufälliges Geheimnis (den Verifier), sendet dessen SHA-256-Hash (die Challenge) mit der Autorisierungsanfrage und weist beim Einlösen des Codes den Besitz des Verifiers nach. Ein Angreifer, der den Code abfängt, kann ihn nicht einlösen.
const verifier = base64url(crypto.getRandomValues(new Uint8Array(32)));
const digest = await crypto.subtle.digest(
"SHA-256", new TextEncoder().encode(verifier)
);
const challenge = base64url(new Uint8Array(digest));
Die Autorisierungsanfrage sollte immer response_type=code enthalten, code_challenge mit code_challenge_method=S256, einen state-Wert, den Sie beim Rücksprung prüfen, und für OIDC zusätzlich scope=openid plus eine nonce, die Sie im ID Token verifizieren. state oder nonce wegzulassen, weil "PKCE das doch abdeckt", ist eine verbreitete Abkürzung. PKCE deckt das meiste ab. Defense in Depth kostet Sie zwei Zufallsstrings.
Client Credentials
Machine to Machine, ohne Benutzerbeteiligung: ein Abrechnungsdienst ruft eine Fakturierungs-API auf, ein Cronjob zieht Berichte. Der Client authentifiziert sich mit eigenen Zugangsdaten und erhält ein Token, das auf ihn selbst beschränkt ist. Zwei Disziplinen zählen hier: Fordern Sie Tokens immer für eine konkrete Audience an, nie universell, und verwahren Sie das Client Secret in einem Vault mit Rotation, nicht in einer Umgebungsdatei, die "nur vorübergehend" eingecheckt wurde.
Device Authorization Grant
Für Geräte mit eingeschränkter Eingabe: Smart-TVs, CLIs, Kiosksysteme. Das Gerät zeigt einen kurzen Code an, der Benutzer bestätigt auf dem Smartphone, das Gerät fragt das Token per Polling ab. Wer schon einmal einen Code auf github.com/login/device eingetippt hat, hat diesen Flow benutzt.
Token Exchange
RFC 8693, für Serviceketten. Dienst A erhält das Token eines Benutzers und muss in dessen Auftrag Dienst B aufrufen. Das Anti-Pattern: Das Originaltoken wird durch fünf Dienste weitergereicht, von denen jeder ein Token akzeptiert, das nie für ihn bestimmt war. Token Exchange erlaubt A, das eingehende Token gegen ein neues einzutauschen, beschränkt auf B, mit der Delegationskette dokumentiert im act-Claim. Nach unserer Erfahrung ist das der Baustein, der in den meisten Microservice-Landschaften fehlt, und der Grund, warum ein einziges gestohlenes Token so oft eine ganze Plattform aufschließt.
Token-Validierung ohne Kompromisse
Access Tokens gibt es in zwei Formaten. Opake Tokens erfordern einen Aufruf des Introspection-Endpunkts (RFC 7662): mehr Latenz, dafür sofortige Sperrung. JWTs werden lokal gegen die veröffentlichten Schlüssel des AS validiert (JWKS): schnell, aber eine Sperrung greift erst zum Ablaufzeitpunkt. Der übliche Kompromiss: JWT Access Tokens mit einer Lebensdauer von 5 bis 15 Minuten plus Refresh-Rotation, Introspection reserviert für besonders schützenswerte Operationen. Und bedenken Sie: JWTs sind kodiert, nicht verschlüsselt. Personenbezogene Daten haben in einem Access Token nichts verloren, das gebietet schon die Datenminimierung nach DSGVO.
Die lokale JWT-Validierung ist der Punkt, an dem Audits schmerzhaft werden. Arbeiten Sie diese Checkliste auf jedem Resource Server ab, jedes Mal:
- Signaturschlüssel vom JWKS-Endpunkt beziehen, per
kidauswählen, mit vernünftiger TTL cachen. Niemals Schlüssel hartkodieren. - Eine Algorithmus-Allowlist festnageln.
RS256oderES256erwarten, alles andere ablehnen. Das erledigtalg: noneund den klassischen Key-Confusion-Angriff von RS256 auf HS256 in einer Zeile. issgegen die exakte Issuer-URL prüfen. Https, keine Überraschungen mit abschließenden Schrägstrichen.- Prüfen, dass
audden Identifier Ihrer API enthält. Ein gültiges Token für die API eines anderen ist kein gültiges Token für Ihre. expundnbfdurchsetzen, mit geringer Toleranz für Uhrenabweichung, 60 bis 120 Sekunden.- Bei ID Tokens zusätzlich verifizieren, dass die
noncemit der gesendeten übereinstimmt, undazpprüfen, wenn mehrere Audiences vorhanden sind. - Dann erst autorisieren. Eine gültige Signatur bedeutet, dass der AS das Token ausgestellt hat. Sie bedeutet nicht, dass dieser Aufrufer diesen Datensatz löschen darf. Scopes und Rollen pro Endpunkt prüfen.
In ASP.NET Core reduziert sich das meiste davon auf Konfiguration:
options.TokenValidationParameters = new TokenValidationParameters
{
ValidIssuer = "https://id.example.com",
ValidAudience = "api://orders",
ValidAlgorithms = new[] { "RS256" },
ClockSkew = TimeSpan.FromSeconds(60)
};
Vergleichbare Einstellungen existieren in jose für Node, spring-security-oauth2-resource-server für Java und authlib für Python. Verwenden Sie eine gepflegte Bibliothek. Handgestricktes JWT-Parsing ist der Weg, auf dem alg: none-Vorfälle entstehen. Für das größere Bild der Endpunkt-Härtung lesen Sie unseren Leitfaden zu API-Sicherheit in der Praxis.
Wo Tokens im Browser leben
Die unbequeme Wahrheit: Es gibt keinen vollständig sicheren Ort für Tokens in Browser-JavaScript. localStorage überlebt einen XSS-Angriff exakt so lange, wie die Exfiltration dauert. Tokens im Arbeitsspeicher sind besser, sterben aber beim Neuladen und fallen trotzdem einer Skript-Injektion zum Opfer, die Ihren HTTP-Client kapert.
Das Muster, das wir für alles Ernsthafte empfehlen, ist Backend for Frontend (BFF). Der OAuth-Tanz findet serverseitig statt. Tokens erreichen den Browser überhaupt nicht. Die SPA erhält ein HttpOnly-, Secure-, SameSite-Cookie, gebunden an eine Server-Session, und das BFF hängt das Access Token an die Upstream-Aufrufe. XSS kann die Session weiterhin missbrauchen, solange die Seite offen ist, aber kein Refresh Token mehr stehlen und mit dauerhaftem Zugriff davonspazieren.
Wo auch immer Refresh Tokens liegen: Rotieren Sie sie. Jeder Refresh stellt ein neues Refresh Token aus und invalidiert das alte. Wird ein bereits verwendetes Token erneut präsentiert, ist das Ihr Diebstahlsignal: die gesamte Token-Familie sperren und eine erneute Authentifizierung erzwingen. Die meisten ausgereiften Anbieter unterstützen das ab Werk, es ist aber häufiger deaktiviert, als man erwarten würde. Sender-constrained Tokens per DPoP gehen einen Schritt weiter und binden Tokens an einen Schlüssel im Besitz des Clients, die Unterstützung dafür wächst stetig.
Fehlerbilder, die wir immer wieder finden
- ID Tokens als API-Berechtigungsnachweis. Der RS akzeptiert jedes JWT mit gültiger Signatur und prüft
audnie. Abhilfe: Audience-Prüfung überall. - Lasches Redirect-URI-Matching. Eine Wildcard plus ein einziger Open Redirect auf irgendeiner passenden Subdomain ergibt gestohlene Authorization Codes.
- Fehlende
stateundnonce. Login-CSRF und Session Fixation, jahrelang still ausnutzbar. - Ein Universaltoken für alle Dienste. Keine Tokens pro Audience, kein Token Exchange. Ein kompromittierter Pod kann alles aufrufen. Genau dieses Versagen soll eine Zero-Trust-Architektur eindämmen.
- Access Tokens mit 24 Stunden Laufzeit und ohne Sperrkonzept. Wenn ein Laptop gestohlen wird, ist "bis morgen warten" kein Incident-Response-Plan, und gegenüber der Aufsichtsbehörde auch kein gutes Argument.
- Mobile Apps mit Custom-URI-Schemes als Redirect. Jede installierte App kann dasselbe Scheme registrieren und den Code abfangen. Verwenden Sie verifizierte HTTPS-Redirects: App Links unter Android, Universal Links unter iOS.
- Client Secrets, ausgeliefert in SPAs und Mobile-Binaries. Public Clients können keine Geheimnisse bewahren. Genau dafür gibt es PKCE.
Selbst bauen, kaufen oder selbst betreiben
Bauen Sie niemals Ihren eigenen Authorization Server. Die Protokolloberfläche (Token-Endpunkte, Consent, Schlüsselrotation, Session-Management, Sperrung) ist riesig und feindselig. Die eigentliche Entscheidung lautet Managed versus Self-Hosted, und im DACH-Raum ist sie untrennbar mit der Datenschutzfrage verbunden:
- Managed (Auth0, Cognito, Entra External ID): am schnellsten produktiv, solide Voreinstellungen, Preismodell pro aktivem Nutzer, das anfangs günstig wirkt und im Wachstum wehtut. Nach unserer Erfahrung beginnt das Preisgespräch meist irgendwo im Bereich einiger zehntausend monatlich aktiver Nutzer. Prüfen Sie außerdem nüchtern, was die DSGVO verlangt: Ein Identity Provider verarbeitet naturgemäß personenbezogene Daten sämtlicher Nutzer. Gibt es eine EU-Region, und liegen auch Logs und Backups dort? Hält der Auftragsverarbeitungsvertrag einer Prüfung durch Ihren Datenschutzbeauftragten stand? Bei US-Anbietern gehören Drittlandtransfers und die zugrunde liegenden Garantien in die Risikobewertung, nicht in die Fußnote.
- Self-Hosted (Keycloak, Zitadel, Ory Hydra, Authentik): volle Kontrolle, Datenresidenz im eigenen Rechenzentrum oder bei einem europäischen Hoster, keine Gebühren pro Nutzer. Es ist kein Zufall, dass Keycloak in deutschen Konzernen und Behörden so verbreitet ist und Zitadel als Schweizer Projekt gestartet wurde: Datenhoheit ist hier ein Auswahlkriterium, kein Marketingwort. Dafür verantworten Sie Upgrades, Härtung, Verfügbarkeit und Schlüsselverwaltung selbst. Kalkulieren Sie echte Engineering-Zeit ein, kein Wochenende.
Wofür Sie sich auch entscheiden, bestehen Sie auf: OIDC-Zertifizierung, Unterstützung für PKCE und Refresh-Rotation, Audiences pro API, kurze Token-Laufzeiten unter Ihrer Kontrolle und WebAuthn-Unterstützung, denn das Passwort-Login ist auf dem Weg nach draußen. Wenn Passkeys auf Ihrer Roadmap stehen, und dort gehören sie hin, bleibt OIDC der Transportmechanismus: Unser Beitrag zu Passkeys und passwortloser Authentifizierung zeigt, wie die Teile zusammenpassen.
Das Protokoll ist längst nicht mehr der schwierige Teil. Die Disziplin ist es: exakte Redirects, verpflichtendes PKCE, Audience-beschränkte Tokens, kurze Laufzeiten, Rotation mit Wiederverwendungserkennung und Validierungs-Checklisten, die im Code-Review durchgesetzt werden. Teams, die diese sechs Gewohnheiten verinnerlichen, haben schlicht keine OAuth-Vorfälle mehr.
Wie Innovation T unterstützen kann
Innovation T entwirft und baut Identitätsinfrastruktur als Kerngeschäft: OIDC-Integrationen, BFF-Architekturen für SPAs, Keycloak- und Cloud-IdP-Deployments, Token Exchange für Microservice-Landschaften und Audits bestehender OAuth-Implementierungen gegen die 2.1-Baseline. Wir haben die oben beschriebenen Fehlerbilder in freier Wildbahn gesehen, und wir wissen, wie man sie schließt, ohne die Sessions Ihrer Benutzer zu zerstören.
Ob Sie einen Identity Provider auswählen, einen Legacy-Implicit-Flow entwirren oder eine API-Landschaft härten wollen: Sehen Sie sich unsere Leistungen an oder sprechen Sie mit unserem Team. Wir sagen Ihnen unverblümt, was zuerst zu beheben ist.
Bereit, mit Innovation T zu bauen?
Ob Sicherheit, Wachstum oder Engineering, unser Team hilft Ihnen, es gut umzusetzen.