„Keycloak meldet die Person an. Der Matrix Authentication Service (MAS) macht daraus eine Matrix-Sitzung. Danach kommuniziert unser Frontend über das Matrix Client-Server API mit dem Homeserver. Ob jemand lesen, schreiben, einladen oder verwalten darf, entscheidet Matrix pro Raum — nicht die UI und nicht allein Keycloak.“
Erklären, ohne sich zu verheddern.
Der direkte Spickzettel für das Meeting. Erst die Antwort, dann die Technik.
Die 60-Sekunden-Version
Keycloak / KIKA
Wer ist die Person? Login, MFA, Gruppen, Business-Rollen, Tenant.
MAS
OAuth/OIDC für Matrix. Verknüpft die Identität mit dem Matrix-Account und gibt dem Client Matrix-Tokens.
Matrix Homeserver
Räume, Events, History, Sync, Mitglieder und tatsächliche Raumrechte.
Wie der Login wirklich läuft
„Wir nehmen einfach das Keycloak-Access-Token und schicken es an Matrix.“
Das sind unterschiedliche Vertrauensbereiche und Token-Zielgruppen.
„Unser Matrix-Client authentifiziert sich bei MAS; MAS nutzt Keycloak als vorgelagerten Identity Provider.“
Das Produkt-SSO macht den Übergang komfortabel.
Berechtigungen: Wer darf was?
Login beantwortet nur „Wer bist du?“
Raum-Mitgliedschaft + Join Rules + Power Levels beantworten „Was darfst du hier?“
1 · Reinkommen
m.room.join_rules
Für vertrauliche Chats meist invite. Ohne Einladung kein Beitritt.
2 · Mitglied sein
m.room.member
Die Person muss tatsächlich joined sein. Ein Keycloak-Claim macht sie nicht automatisch zum Raum-Mitglied.
3 · Aktion ausführen
m.room.power_levels
Definiert Schwellen für Nachrichten, State, Invite, Kick, Ban, Redact usw.
| Produktrolle | Matrix-Behandlung | Typisch | Darf normalerweise |
|---|---|---|---|
| Gast / KundeKein „echter Matrix Guest“, sondern normal angemeldeter Produktnutzer | Nur eingeladen, normaler Matrix-Account | PL 0 | Lesen und schreiben, wenn Raumvorlage es erlaubt |
| BeraterInterner Standardnutzer | Zugewiesene Räume | PL 10–20 | Schreiben; Einladungen besser über Backend |
| ModeratorRaumbezogene Verantwortung | Erhöhtes Power Level in genau diesem Raum | PL 50 | Name/Topic, Kick, Redact — je nach Vorlage |
| Tenant-AdminMandantenweite Administration | Backend-Orchestrierung + erhöhte PLs | PL 75 | Mitglieder/Moderatoren verwalten |
| Service UserChat-Orchestrator | Technischer Account, streng geschützt | PL 100 | Räume anlegen, Mitglieder und Vorlagen setzen |
Was passiert beim Nachrichtenschreiben?
Frontend → PUT /_matrix/client/v3/rooms/{roomId}/send/m.room.message/{txnId} → Homeserver prüft Token, Membership und Power Level → Event wird gespeichert und synchronisiert.
Der Server prüft
- Ist das Access-Token gültig?
- Ist der User im Raum?
- Darf er
m.room.messagesenden? - Ist das Event nach Raumversion/State zulässig?
Das Frontend macht
- Composer deaktivieren, wenn Schreiben nicht erlaubt ist
- Optimistic UI anzeigen
- Fehler wie
M_FORBIDDENsauber behandeln - Niemals UI-Sperren als echte Security verkaufen
Frontend / Read Component einbinden
Ein MatrixClient pro angemeldeter Browser-Session. Nicht in jeder Komponente neu erzeugen. Oben als Service/Provider halten; Read- und Write-Komponenten bekommen client + roomId.
Read Component
- Raum aus dem Client holen
- Bestehende Timeline rendern
- Auf neue Timeline-Events hören
- Beim Unmount Listener entfernen
- Pagination separat über Scroll/„ältere laden“
Write Component
- Vorab
maySendEventfür UX prüfen - Nachricht mit eindeutiger Transaktions-ID senden
- Pending/Sent/Failed anzeigen
- Serverfehler bleibt die letzte Wahrheit
// Einmal zentral nach erfolgreichem MAS/OIDC-Login const client = createClient({ baseUrl: homeserverUrl, accessToken: matrixAccessToken, userId: matrixUserId, deviceId }); await client.startClient({ initialSyncLimit: 20 }); // Read Component: vorhandene + neue Events const room = client.getRoom(roomId); const events = room?.getLiveTimeline().getEvents() ?? []; const onTimeline = (event, eventRoom) => { if (eventRoom?.roomId === roomId) renderOrAppend(event); }; client.on(RoomEvent.Timeline, onTimeline); // Cleanup: client.off(RoomEvent.Timeline, onTimeline) // Write Component: UX-Check + echter Server-Check const canWrite = room?.currentState.maySendEvent( EventType.RoomMessage, client.getUserId() ); await client.sendEvent(roomId, EventType.RoomMessage, { msgtype: MsgType.Text, body: "Hallo" });
Was gehört wohin?
| Baustein | Verantwortung | Nicht seine Aufgabe |
|---|---|---|
| Keycloak / KIKA | Identität, MFA, Produktrollen, Gruppen, Tenant-Kontext | Matrix-Raumrechte direkt durchsetzen |
| MAS | Matrix OAuth/OIDC, Clients, Sessions, Token, Account-Verknüpfung | Pro Raum entscheiden, wer schreiben darf |
| Homeserver | Client API, Sync, Räume, Events, Membership, Power Levels | Eure Business-Prozesse verstehen |
| Chat-Orchestrator / Backend | Businessrolle → Matrix-Account, Einladung, Raumvorlage, Power Level | Chat-Timeline im Browser rendern |
| Web Component | UX, Timeline, Composer, lokale Statusanzeige | Sicherheitsgrenze sein |
Wahrscheinliche Fragen — kurze Antworten
„Warum brauchen wir MAS, wenn wir schon Keycloak haben?“
Keycloak authentifiziert Menschen für eure Produktlandschaft. MAS ist der OAuth/OIDC-Authorization-Server für Matrix-Clients und übersetzt den Upstream-Login in eine Matrix-Sitzung. Dadurch müssen Clients nicht Matrix-spezifische Logik in Keycloak nachbauen.
„Muss sich der Nutzer zweimal anmelden?“
Technisch laufen zwei Sicherheitskontexte. Praktisch meist kein zweites Passwort: MAS leitet zu Keycloak, die bestehende SSO-Session wird erkannt, und der Redirect kommt direkt zurück.
„Kann eine angemeldete Person automatisch alle Chats lesen?“
Nein. Ein gültiger Login gibt nur eine Identität. Zugriff entsteht durch Raum-Mitgliedschaft und Join Rules. Private Räume sollten invite-only und nicht im öffentlichen Directory sein.
„Kann das Frontend das Schreiben verbieten?“
Für gute UX: ja. Als Security: nein. Ein Nutzer könnte das Matrix API direkt aufrufen. Der Homeserver muss über m.room.power_levels ablehnen.
„Woher weiß die Read Component, was neu ist?“
Der zentrale MatrixClient synchronisiert laufend. Die Komponente rendert die Live-Timeline des Raums und hört auf Timeline-Events. Alte Historie wird paginiert nachgeladen.
„Wer legt Räume an und lädt Leute ein?“
Empfehlung: euer Backend/Chat-Orchestrator. So sind Tenant-Grenzen, Raumvorlagen, Audit und Rollenmapping konsistent. Nicht jede Web Component sollte frei Räume erstellen.
„Sind Spaces unsere Berechtigungsstruktur?“
Nein. Spaces sind vor allem Navigation und Hierarchie. Sicherheit bleibt bei Membership, Join Rules und Power Levels.
„Brauchen wir einen Homeserver pro Tenant?“
Meist nicht am Anfang. Ein Homeserver pro Umgebung mit sauberer logischer Tenant-Isolation ist einfacher. Separate Server nur bei regulatorischer, vertraglicher oder technischer Isolationspflicht.
„Was ist mit Ende-zu-Ende-Verschlüsselung?“
Dann kommen Geräte, Schlüssel-Backup, Recovery und Verifikation dazu. Die Read Component muss Crypto initialisieren; Support/Audit werden komplexer. Das ist eine bewusste Produktentscheidung, kein kostenloser Schalter.
Diese Entscheidungen müssen wir noch treffen
Wer darf einladen?
Backend only für Audit — oder Berater direkt für Komfort?
Wer erstellt Räume?
Empfehlung: Orchestrator mit festen Templates und Tenant-Prüfung.
E2EE?
Ja/Nein entscheidet über Geräte-, Backup-, Recovery- und Support-Konzept.
Federation?
Nur aktivieren, wenn externe Matrix-Interoperabilität wirklich gebraucht wird.
History / Retention?
Wer sieht alte Nachrichten, wie lange bleiben sie, wie wird exportiert?
Rollenmapping?
Keycloak-Claims serverseitig auf Membership und Power Levels abbilden.