Setup Auth via Keycloak
此内容尚不支持你的语言。
Nach dem technischen Skeleton läuft die Turnier-App als Preview-System. Frontend, API Gateway, Service, Datenbank und RabbitMQ starten. Das ist noch keine Fachlichkeit, aber es ist ein wichtiger technischer Durchstich.
Der nächste Schritt wirkt auf den ersten Blick wieder nach Infrastruktur.
Authentifizierung.
Also Login. Token. Guards. Interceptor. JWT Strategy. Keycloak-Konfiguration.
Nicht besonders aufregend. Zumindest nicht im Vergleich zu einer Drag-and-Drop-Gruppeneinteilung oder einem Spielplan-Generator.
Trotzdem gehört Auth für dieses Projekt früh in die Reise. Denn sobald personenbezogene oder vereinsbezogene Daten ins Spiel kommen, ist die Frage nicht mehr nur:
Kann die App etwas anzeigen?
Sondern:
Wer darf welche Daten sehen oder verändern?
Warum Auth so früh?
Abschnitt betitelt „Warum Auth so früh?“Die Turnier-App wird nicht nur eine öffentliche Ergebnisliste. Sie verwaltet perspektivisch Spieler, Turniere, Gruppen, Ergebnisse und Historie.
Ein Teil dieser Daten ist harmlos. Ein anderer Teil ist sensibel genug, dass man nicht beliebig damit umgehen sollte. Gerade weil es um Kinderturniere geht, ist Datensparsamkeit wichtig. Aber auch datensparsame Anwendungen brauchen Zugriffsschutz.
Für den MVP heißt das noch nicht, dass jede Rollenregel perfekt ausmodelliert sein muss.
Es heißt aber:
- nicht jeder darf Spieler verwalten
- nicht jeder darf Turniere anlegen
- nicht jeder darf Ergebnisse erfassen
- Eltern oder Zuschauer sollen später maximal eine begrenzte Live-Ansicht sehen
- technische Datenzugriffe müssen vorbereitet werden
Der Login ist also nicht nur ein Komfort-Feature. Er ist die Grundlage dafür, dass spätere Fachlichkeit sauber abgesichert werden kann.
Authentifizierung ist nicht Autorisierung
Abschnitt betitelt „Authentifizierung ist nicht Autorisierung“Ein häufiger Fehler ist, Login und Rechteprüfung in einen Topf zu werfen.
Authentifizierung beantwortet:
Wer bist du?
Autorisierung beantwortet:
Was darfst du?
In diesem Schritt geht es vor allem um Authentifizierung und um die technische Vorbereitung späterer Autorisierung.
Der Nutzer soll sich anmelden können. Das Frontend soll ein Access Token erhalten. Das API Gateway soll dieses Token validieren. Danach soll im Request-Kontext ein authentifizierter Benutzer verfügbar sein.
Rollen wie admin, trainer, referee oder parent sind bereits als Richtung bekannt. Aber die vollständige fachliche Rollenlogik entsteht später.
Das ist bewusst so.
Auch hier gilt wieder: erst der technische Durchstich, dann die Fachlichkeit.
Warum Keycloak?
Abschnitt betitelt „Warum Keycloak?“Für das Projekt nutze ich Keycloak als Identity Provider.
Das hat mehrere Gründe.
Zum einen ist Keycloak in meinem Architektur-Labor bereits bekannt. Ich muss also nicht zuerst einen neuen Auth-Anbieter evaluieren oder eine eigene Login-Lösung bauen. Zum anderen unterstützt Keycloak etablierte Standards wie OpenID Connect und OAuth 2.0.
Für eine moderne Web-App ist vor allem der Authorization Code Flow mit PKCE relevant. Das Frontend bekommt dadurch einen nutzerfreundlichen Login über den Browser, ohne selbst Passwörter zu verarbeiten. Das Backend bekommt ein signiertes Access Token, das es unabhängig validieren kann.
Das ist aus Entwickler- und Nutzersicht angenehm:
- Nutzer melden sich über eine bekannte Login-Seite an
- das Frontend muss keine Passwörter speichern
- das Backend bekommt standardisierte JWTs
- Rollen und Claims können zentral verwaltet werden
- später können weitere Clients ergänzt werden
Keycloak ist dabei nicht immer intuitiv. Gerade ein neuer Realm mit neuen Clients, Scopes und Mappern ist schnell eingerichtet, aber nicht unbedingt sofort richtig eingerichtet.
Genau deshalb ist dieser Schritt einen eigenen Feldbericht wert.
Zielbild
Abschnitt betitelt „Zielbild“Für die Turnier-App entsteht in diesem Schritt folgende Kette:
Angular App ↓ Login via KeycloakAccess Token ↓ Bearer Token per HTTP InterceptorTournament API Gateway ↓ JWT Strategy / GuardAuthenticatedUser im Request-KontextDas Frontend kümmert sich um Login, Logout und das Mitsenden des Tokens.
Das API Gateway validiert das Token. Nicht das Frontend entscheidet, ob ein Nutzer gültig ist. Das Backend prüft Signatur, Issuer, Audience und Ablaufzeit.
Das ist wichtig.
Ein Frontend kann Benutzeroberflächen ausblenden. Aber es darf nie die letzte Instanz für Zugriffsschutz sein.
Angular: Keycloak initialisieren und Token mitsenden
Abschnitt betitelt „Angular: Keycloak initialisieren und Token mitsenden“Im Frontend wird Keycloak in die Angular-Standalone-App integriert.
Der grobe technische Schnitt:
- Keycloak-Konfiguration über Environment- oder Runtime-Config
- Initialisierung beim App-Start
- Auth Guard für geschützte Routen
- HTTP Interceptor für API Requests
- Login-/Logout-Möglichkeit in der App-Shell
Der Interceptor ist dabei unspektakulär, aber zentral.
Er sorgt dafür, dass Requests an die Tournament API automatisch ein Bearer Token erhalten:
Authorization: Bearer <access-token>Damit muss nicht jedes Feature selbst wissen, wie Auth technisch funktioniert. Spielerverwaltung, Turnierliste oder Turniertag sollen später fachlich arbeiten können. Die Token-Mechanik bleibt eine Querschnittsfunktion.
Das ist genau der Punkt eines guten Skeletons: Es reduziert spätere Reibung.
Ein späterer Feature-Prompt muss nicht mehr lauten:
Baue die Spielerverwaltung und integriere nebenbei Login, Token, Guards und API-Auth.
Sondern nur noch:
Baue die Spielerverwaltung innerhalb der bestehenden Auth-Struktur.
API Gateway: JWT Strategy, Passport und Guards
Abschnitt betitelt „API Gateway: JWT Strategy, Passport und Guards“Das API Gateway ist die einzige externe Backend-Schnittstelle für das Frontend.
Hier wird das Access Token validiert.
Technisch passiert das über eine JWT Strategy, Passport und Guards. Der Guard schützt Routen. Die Strategy prüft das Token und erzeugt daraus einen internen Benutzerkontext.
Ein vereinfachtes Zielmodell sieht so aus:
export interface AuthenticatedUser { userId: string; subject: string; username?: string; email?: string; roles: string[];}Wichtig ist dabei: userId und subject kommen aus dem sub-Claim des Tokens.
Nicht aus der E-Mail-Adresse.
Nicht aus dem Anzeigenamen.
Nicht aus preferred_username.
Diese Werte dürfen angezeigt oder für Debugging genutzt werden. Aber sie sind keine stabile technische Identität.
Warum sub so wichtig ist
Abschnitt betitelt „Warum sub so wichtig ist“Für spätere Datenzugriffe braucht das Backend eine stabile Benutzerkennung.
Wenn ein Trainer ein Turnier anlegt, ein Kampfrichter Ergebnisse erfasst oder ein Nutzer später nur eigene Daten sehen darf, braucht das System einen verlässlichen Bezug:
created_by_user_idupdated_by_user_idowner_user_idOder neutraler:
created_by_subjectupdated_by_subjectowner_subjectDie konkrete Benennung ist weniger wichtig als die Quelle.
Die technische Benutzer-ID soll aus sub kommen.
sub steht für Subject und ist im OpenID-Connect-Kontext die stabile Identität des authentifizierten Benutzers innerhalb des Identity Providers.
Für dieses Projekt gilt daher:
Technische User-ID = token.subWenn sub fehlt, soll das API Gateway nicht stillschweigend auf email oder preferred_username ausweichen. Es soll den Request ablehnen.
Das ist unbequem, aber richtig.
Denn ein fehlender stabiler Identity-Claim ist kein fachlicher Sonderfall. Es ist eine fehlerhafte Auth-Konfiguration.
Datenzugriff vorbereiten
Abschnitt betitelt „Datenzugriff vorbereiten“Noch gibt es keine echte Spielerverwaltung, keine Turnierdaten und keine Ergebnislogik.
Trotzdem ist dieser Schritt fachlich relevant.
Denn sobald später Daten entstehen, kann das Backend sie mit dem authentifizierten Nutzer verknüpfen.
Beispiele:
Ein Trainer sieht nur Turniere seines Vereins.Ein Kampfrichter darf nur Ergebnisse für ein aktives Turnier erfassen.Ein Eltern-Link sieht nur freigegebene Live-Daten.Ein Nutzer sieht nur Daten, für die er berechtigt ist.Für den Anfang ist das noch Zukunftsmusik. Aber ohne saubere Auth-Grundlage würde diese Zukunft sehr schnell wackelig.
Der Login ist also nicht das Ende der Sicherheitsarchitektur. Er ist ihr Anfang.
Manuelles Setup im Keycloak Admin
Abschnitt betitelt „Manuelles Setup im Keycloak Admin“Ein Teil dieses Schritts passiert bewusst nicht im Code.
Der Realm und die Clients werden im Keycloak Admin angelegt.
Für dieses Projekt bedeutet das:
Realm:tournament
Frontend Client:tournament-frontend
API Client:tournament-apiDer Frontend-Client nutzt den Authorization Code Flow mit PKCE. Redirect URIs und Web Origins müssen für lokale Entwicklung und Preview-Umgebung passen.
Das API Gateway erwartet ein Access Token, das für die Tournament API gedacht ist.
Und genau hier steckt ein typischer Keycloak-Stolperstein.
Stolperstein: gültiges Token, falsche Audience
Abschnitt betitelt „Stolperstein: gültiges Token, falsche Audience“Nach der ersten Integration funktionierte der Login im Frontend. Auch sub war im Access Token vorhanden.
Trotzdem lehnte das API Gateway den Request auf /auth/me ab.
Der Guard loggte sinngemäß:
jwt audience invalid. expected: tournament-apiDas Token war also nicht grundsätzlich ungültig.
Es war signiert. Es hatte einen Issuer. Es hatte ein Subject. Es war ein echtes Access Token.
Aber es war nicht für diese API ausgestellt.
Im Token stand als Audience:
"aud": "account"Das API Gateway erwartete aber:
tournament-apiDas ist ein wichtiger Unterschied.
Ein Token kann gültig sein und trotzdem nicht für den Empfänger bestimmt sein.
Die Lösung war ein Audience Mapper in Keycloak. Der Frontend-Client beziehungsweise ein zugewiesener Client Scope sorgt dafür, dass tournament-api als Audience im Access Token landet.
Danach enthält das Token sinngemäß:
"aud": ["account", "tournament-api"]oder je nach Konfiguration:
"aud": "tournament-api"Erst dann akzeptiert die API das Token.
Warum die Audience-Prüfung wichtig bleibt
Abschnitt betitelt „Warum die Audience-Prüfung wichtig bleibt“Man könnte das API Gateway auch lockerer konfigurieren und die Audience-Prüfung entfernen.
Das wäre bequemer.
Aber es wäre die falsche Richtung.
Die Audience beantwortet die Frage:
Für wen ist dieses Token gedacht?
Wenn ein Backend Tokens akzeptiert, die nicht für dieses Backend bestimmt sind, wird die Sicherheitsgrenze unschärfer. Gerade in einem System mit mehreren Apps, APIs oder späteren Clients sollte das API Gateway nicht nur prüfen, ob ein Token gültig ist, sondern auch, ob es für diese API bestimmt ist.
Deshalb bleibt die Audience-Prüfung aktiv.
Das Keycloak-Setup wird angepasst, nicht die API-Validierung verwässert.
Ergebnis des Auth-Durchstichs
Abschnitt betitelt „Ergebnis des Auth-Durchstichs“Am Ende dieses Schritts funktioniert die Auth-Kette:
Frontend Login ↓Access Token enthält sub ↓Access Token enthält aud: tournament-api ↓HTTP Interceptor sendet Bearer Token ↓API Gateway validiert JWT ↓/auth/me liefert den authentifizierten BenutzerDamit ist noch keine fachliche Rollenlogik implementiert.
Aber die Basis steht.
Das API Gateway weiß jetzt, wer den Request stellt. Es kann später Rollen auswerten. Es kann Datenzugriffe auf den authentifizierten Benutzer beziehen. Und es kann Requests ablehnen, wenn die Identität nicht sauber belegt ist.
Was bewusst noch offen bleibt
Abschnitt betitelt „Was bewusst noch offen bleibt“Auch dieser Schritt bleibt begrenzt.
Nicht enthalten:
- keine vollständige Rollenmatrix
- keine fachliche Berechtigungsprüfung je Use Case
- keine Vereins- oder Mandantenlogik
- keine Eltern-Live-Freigaben
- keine Spieler- oder Turnierdaten
- keine UI für Rechteverwaltung
Das ist kein Mangel. Es ist Absicht.
Der Schritt soll Auth technisch tragfähig machen. Die fachliche Autorisierung entsteht später, wenn die konkreten Use Cases gebaut werden.
Review-Fragen
Abschnitt betitelt „Review-Fragen“Bei Auth-Integrationen reicht es nicht, wenn der Login optisch funktioniert.
Wichtige Review-Fragen in diesem Schritt:
- Wird der Authorization Code Flow mit PKCE verwendet?
- Kommt die Konfiguration aus Environment- oder Runtime-Config?
- Werden keine URLs hart codiert?
- Sendet der Interceptor Tokens nur an passende API-Ziele?
- Validiert das API Gateway Signatur, Issuer, Audience und Ablaufzeit?
- Wird
subals stabile technische User-ID verwendet? - Gibt es keinen stillen Fallback auf E-Mail oder Anzeigename?
- Werden Rollen aus dem Token extrahiert, aber noch nicht überinterpretiert?
- Ist
/auth/megeschützt? - Scheitert ein Request ohne Token?
- Scheitert ein Request mit falscher Audience?
- Funktioniert das Setup lokal und in der Preview?
Gerade bei Keycloak lohnt sich dieses Review. Die Admin-Oberfläche erlaubt viele Kombinationen, die technisch funktionieren, aber fachlich nicht sauber sind.
Auth ist ein klassischer Infrastruktur-Schritt.
Man sieht danach keine Turnierliste. Keine Gruppen. Keine Ergebnisse. Keine hübsche Elternansicht.
Trotzdem ist der Schritt wichtig.
Denn ab jetzt kann das System nicht nur laufen. Es kann Requests einem Benutzer zuordnen. Es kann später Datenzugriffe einschränken. Es kann Rollen auswerten. Und es kann verhindern, dass ein gültiges, aber falsch adressiertes Token einfach akzeptiert wird.
Keycloak ist dabei nicht immer intuitiv. Gerade neue Realms, Client Scopes, Mapper und Audiences sind Stolpersteine, wenn man sie nicht schon ein paar Mal eingerichtet hat.
Aber genau deshalb gehört dieser Schritt in die Reise.
Nicht als Hochglanz-Auth-Tutorial.
Sondern als realer Feldbericht:
Login ist erst dann fertig, wenn das Backend dem Token aus gutem Grund vertraut.