Skip to content

Setup Auth via Keycloak

This content is not available in your language yet.

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?

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.

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.

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.

Für die Turnier-App entsteht in diesem Schritt folgende Kette:

Angular App
↓ Login via Keycloak
Access Token
↓ Bearer Token per HTTP Interceptor
Tournament API Gateway
↓ JWT Strategy / Guard
AuthenticatedUser im Request-Kontext

Das 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.

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.

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_id
updated_by_user_id
owner_user_id

Oder neutraler:

created_by_subject
updated_by_subject
owner_subject

Die 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.sub

Wenn 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.

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.

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-api

Der 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.

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-api

Das 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-api

Das 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.

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.

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 Benutzer

Damit 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.

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.

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 sub als 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/me geschü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.