From 37cab43f2ce53ed8e41929e5b170e72e6e9c4655 Mon Sep 17 00:00:00 2001 From: Christoph Date: Sun, 27 Sep 2026 17:43:44 +0200 Subject: [PATCH] Add 'README-mobile-oidc-bridge-readme.docx' and 'README-mobile-oidc-bridge-readme.md'. --- README-mobile-oidc-bridge-readme.docx | Bin 0 -> 44902 bytes README-mobile-oidc-bridge-readme.md | 691 ++++++++++++++++++++++++++ 2 files changed, 691 insertions(+) create mode 100644 README-mobile-oidc-bridge-readme.docx create mode 100644 README-mobile-oidc-bridge-readme.md diff --git a/README-mobile-oidc-bridge-readme.docx b/README-mobile-oidc-bridge-readme.docx new file mode 100644 index 0000000000000000000000000000000000000000..d18c6ba3aee6ed5ada5e7b839f6db0119e3c8446 GIT binary patch literal 44902 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 literal 0 HcmV?d00001 diff --git a/README-mobile-oidc-bridge-readme.md b/README-mobile-oidc-bridge-readme.md new file mode 100644 index 0000000..99a2ada --- /dev/null +++ b/README-mobile-oidc-bridge-readme.md @@ -0,0 +1,691 @@ +# Mattermost OIDC Mobile Bridge + +## Zweck + +Diese Dokumentation beschreibt die Installation und Konfiguration der `mobile-bridge` aus dem Projekt `mattermost-oidc` für eine native Mattermost-Mobile-App. + +Die Bridge wird benötigt, wenn Mattermost für die Anmeldung das Plugin `mattermost-oidc` verwendet, die native Mobile-App aber den eingebauten Mattermost-OpenID-Endpunkt erwartet. Die Bridge verändert Mattermost selbst nicht. Sie fängt nur zwei HTTP-Endpunkte ab: + +- `/api/v4/config/client` +- `/oauth/openid/mobile_login` + +Für die native Mattermost-App wird in der Client-Konfiguration `EnableSignUpWithOpenId=true` signalisiert. Der Mobile-Login wird anschließend zum `mattermost-oidc`-Plugin umgeleitet. + +Web- und Desktop-Clients bleiben unverändert. + +## Versions- und Umgebungsvariablen + +Die Anleitung ist bewusst versionsunabhängig aufgebaut. Vor Beginn werden die für die jeweilige Installation gültigen Versionen, URLs und Pfade einmal in der aktuellen Root-Shell gesetzt. Die nachfolgenden Befehle verwenden diese Variablen. + +```bash +export MM_VER="11.7.11" +export MM_OIDC_VER="0.6.1" +export MM_SITE_URL="https://mm.nd.digital" + +export MM_SRC_BASE="/usr/local/src/mattermost-oidc" +export MM_OIDC_REPO="https://github.com/server-camp/mattermost-oidc-plugin.git" +export MM_OIDC_SRC="${MM_SRC_BASE}/mattermost-oidc-plugin-${MM_OIDC_VER}" + +export MM_UPSTREAM="http://127.0.0.1:8065" +export MM_BRIDGE_LISTEN="127.0.0.1:8066" + +export MM_BRIDGE_BIN_DIR="/usr/local/sbin" +export MM_BRIDGE_BIN="${MM_BRIDGE_BIN_DIR}/mattermost-oidc-mobile-bridge-${MM_OIDC_VER}" +export MM_BRIDGE_LINK="${MM_BRIDGE_BIN_DIR}/mattermost-oidc-mobile-bridge" +``` + +`MM_VER` dokumentiert die aktuell eingesetzte Mattermost-Version. Für Download und Build der Bridge ist insbesondere `MM_OIDC_VER` relevant. Bei einer späteren Aktualisierung wird die gewünschte Version im Variablenblock geändert und der Ablauf mit dem neuen Release wiederholt. + +Die hier beschriebene Installation wurde mit den oben beispielhaft eingetragenen Versionen getestet. Weitere Rahmenbedingungen waren Debian 13, nginx als Reverse Proxy, Mattermost auf `127.0.0.1:8065`, die Mobile Bridge auf `127.0.0.1:8066` und Keycloak als OIDC-Provider. + +Die Bridge benötigt **kein eigenes OIDC-Client-Secret**. Client-ID, Client-Secret und Kommunikation mit dem OIDC-Provider bleiben Aufgabe des `mattermost-oidc`-Plugins. + +## Funktionsweise + +Der relevante Ablauf ist: + +```text +Mattermost Mobile App + | + | GET /api/v4/config/client + v + nginx + | + +--> mobile-bridge :8066 + | + +--> Mattermost :8065 + | + +--> bei Mobile User-Agent: + EnableSignUpWithOpenId=true + +Mobile App + | + | /oauth/openid/mobile_login?redirect_to=mmauth://callback + v + nginx + | + +--> mobile-bridge :8066 + | + +--> 302 /plugins/mattermost-oidc/oauth2/connect + ?mobile_redirect=mmauth://callback + | + v + Keycloak + | + v + /plugins/mattermost-oidc/oauth2/callback + | + v + mmauth://callback + | + v + Mattermost App +``` + +Alle anderen Requests, insbesondere REST, WebSocket, Dateien und `/plugins/...`, gehen weiterhin direkt an Mattermost. + +## Voraussetzungen + +Vor Installation der Bridge müssen folgende Bedingungen erfüllt sein: + +1. Das Plugin `mattermost-oidc` ist installiert und aktiviert. +2. Der normale OIDC-Web-Login funktioniert bereits vollständig. +3. Der OIDC-Provider ist korrekt eingerichtet. +4. Die bestehende Redirect-URI des Plugins funktioniert: + `/plugins/mattermost-oidc/oauth2/callback` +5. nginx leitet die normale Mattermost-Site bereits auf `127.0.0.1:8065` weiter. +6. Go ist zum Bauen der Bridge verfügbar. + +Die benötigte Go-Version ist nicht in dieser Anleitung fest verdrahtet. Nach dem Download wird sie direkt aus `mobile-bridge/go.mod` abgelesen. Falls die Debian-Standardversion nicht ausreicht, kann eine passende Go-Version beispielsweise aus den Debian-Backports verwendet werden. + +## 1. Quellcode herunterladen + +Das Repository wird versionsbezogen unter `MM_SRC_BASE` abgelegt. Dadurch können mehrere Release-Stände parallel vorhanden sein und die Herkunft einer installierten Binary bleibt nachvollziehbar. + +Arbeitsverzeichnis anlegen: + +```bash +mkdir -p "$MM_SRC_BASE" +``` + +Gewünschten Release-Tag direkt in ein versionsbezogenes Verzeichnis klonen: + +```bash +git clone --branch "v${MM_OIDC_VER}" --depth 1 \ + "$MM_OIDC_REPO" \ + "$MM_OIDC_SRC" +``` + +Ausgecheckten Stand kontrollieren: + +```bash +cd "$MM_OIDC_SRC" +git status +git describe --tags --exact-match +``` + +Bei einem direkt ausgecheckten Release-Tag ist ein `detached HEAD` normal. `git describe --tags --exact-match` sollte `v${MM_OIDC_VER}` ausgeben. + +Die Mobile Bridge befindet sich anschließend unter: + +```text +${MM_OIDC_SRC}/mobile-bridge +``` + +## 2. Go installieren + +Benötigte Go-Version aus dem Release ermitteln: + +```bash +awk '/^go / {print "benötigte Go-Version:", $2}' \ + "$MM_OIDC_SRC/mobile-bridge/go.mod" +``` + +Installierte Version prüfen: + +```bash +go version +``` + +Falls die vorhandene Go-Version nicht ausreicht, eine passende Version installieren. Unter Debian 13 kann - sofern `trixie-backports` bereits konfiguriert ist - beispielsweise verwendet werden: + +```bash +apt install -t trixie-backports golang-go +``` + +Danach erneut prüfen: + +```bash +go version +``` + +## 3. Mobile Bridge bauen + +In das Bridge-Verzeichnis wechseln: + +```bash +cd "$MM_OIDC_SRC/mobile-bridge" +``` + +Binary bauen: + +```bash +go build -o mobile-bridge . +``` + +Ergebnis kontrollieren: + +```bash +file mobile-bridge +ls -lh mobile-bridge +``` + +## 4. Bridge vor der Installation manuell testen + +Port 8066 sollte zunächst frei sein: + +```bash +ss -lntp | grep ':8066' +``` + +Die Bridge testweise nur auf Loopback starten: + +```bash +LISTEN="$MM_BRIDGE_LISTEN" UPSTREAM="$MM_UPSTREAM" ./mobile-bridge +``` + +Die Bindung an `127.0.0.1` ist beabsichtigt. Die Bridge muss nicht direkt aus dem Internet erreichbar sein; nginx ist der öffentliche Einstiegspunkt. + +### Mobile Client-Konfiguration testen + +In einem zweiten Terminal: + +```bash +curl -s -A 'Mattermost Mobile/' \ + http://127.0.0.1:8066/api/v4/config/client | + grep -o '"EnableSignUpWithOpenId":"[^"]*"' +``` + +Erwartet: + +```text +"EnableSignUpWithOpenId":"true" +``` + +Mit einem Browser-User-Agent: + +```bash +curl -s -A 'Mozilla/5.0' \ + http://127.0.0.1:8066/api/v4/config/client | + grep -o '"EnableSignUpWithOpenId":"[^"]*"' +``` + +Bei der dokumentierten Konfiguration war das Ergebnis: + +```text +"EnableSignUpWithOpenId":"false" +``` + +Damit ist sichergestellt, dass die Änderung nur für die Mobile-App erfolgt. + +### Mobile-Login-Redirect testen + +```bash +curl -si \ + 'http://127.0.0.1:8066/oauth/openid/mobile_login?redirect_to=mmauth%3A%2F%2Fcallback' | + head -20 +``` + +Erwartet wird HTTP 302 mit einem `Location`-Header in Richtung: + +```text +/plugins/mattermost-oidc/oauth2/connect?mobile_redirect=mmauth%3A%2F%2Fcallback +``` + +Danach den manuellen Prozess mit `Ctrl-C` beenden. + +## 5. Binary versionsbezogen installieren + +Die gebaute Bridge wird mit ihrer Plugin-/Bridge-Version im Dateinamen unter `/usr/local/sbin` installiert. Ein stabiler Symlink ohne Versionsnummer zeigt auf die aktuell aktive Binary. Dadurch kann ein Update oder Rollback durch Umschalten des Symlinks erfolgen, während die systemd-Unit unverändert bleibt. + +Binary installieren: + +```bash +install -o root -g root -m 755 \ + mobile-bridge \ + "$MM_BRIDGE_BIN" +``` + +Stabilen Symlink auf diese Version setzen: + +```bash +ln -sfn "$(basename "$MM_BRIDGE_BIN")" "$MM_BRIDGE_LINK" +``` + +Ergebnis kontrollieren: + +```bash +ls -l "$MM_BRIDGE_BIN" "$MM_BRIDGE_LINK" +readlink -f "$MM_BRIDGE_LINK" +``` + +Beispiel für Version `0.6.1`: + +```text +/usr/local/sbin/mattermost-oidc-mobile-bridge-0.6.1 +/usr/local/sbin/mattermost-oidc-mobile-bridge -> mattermost-oidc-mobile-bridge-0.6.1 +``` + +## 6. systemd-Service einrichten + +Datei anlegen: + +```text +/etc/systemd/system/mattermost-oidc-mobile-bridge.service +``` + +Inhalt: + +```ini +[Unit] +Description=Mattermost OIDC Mobile Bridge +After=network.target mattermost.service +Requires=mattermost.service + +[Service] +Type=simple +User=mattermost +Group=mattermost +Environment=LISTEN=127.0.0.1:8066 +Environment=UPSTREAM=http://127.0.0.1:8065 +ExecStart=/usr/local/sbin/mattermost-oidc-mobile-bridge +Restart=on-failure +RestartSec=5s + +[Install] +WantedBy=multi-user.target +``` + +`ExecStart` verweist bewusst auf den versionsunabhängigen Symlink. Bei einem Update muss die Unit-Datei deshalb nicht geändert werden. + +Konfiguration laden und prüfen: + +```bash +systemctl daemon-reload +systemd-analyze verify /etc/systemd/system/mattermost-oidc-mobile-bridge.service +``` + +Dienst zunächst nur starten: + +```bash +systemctl start mattermost-oidc-mobile-bridge.service +``` + +Status prüfen: + +```bash +systemctl status mattermost-oidc-mobile-bridge.service +ss -lntp | grep ':8066' +``` + +Erwartet wird ein Listener ausschließlich auf: + +```text +127.0.0.1:8066 +``` + +Nach erfolgreichem End-to-End-Test den Autostart aktivieren: + +```bash +systemctl enable mattermost-oidc-mobile-bridge.service +``` + +Kontrolle: + +```bash +systemctl is-enabled mattermost-oidc-mobile-bridge.service +systemctl is-active mattermost-oidc-mobile-bridge.service +``` + +Erwartet: + +```text +enabled +active +``` + +## 7. nginx konfigurieren + +In der dokumentierten Installation ist die aktive Konfiguration: + +```text +/etc/nginx/sites-available/mm.nd.digital.conf +``` + +mit Symlink unter `sites-enabled`. + +Vor der Änderung ein Backup der realen Datei anlegen, nicht nur des Symlinks. + +Vor den allgemeinen Mattermost-`location`-Blöcken werden zwei Exact-Match-Locations eingefügt: + +```nginx +# Mattermost OIDC Mobile Bridge +location = /api/v4/config/client { + proxy_set_header Host $host; + proxy_set_header X-Real-IP $remote_addr; + proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; + proxy_set_header X-Forwarded-Proto $scheme; + proxy_pass http://127.0.0.1:8066; +} + +location = /oauth/openid/mobile_login { + proxy_set_header Host $host; + proxy_set_header X-Real-IP $remote_addr; + proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; + proxy_set_header X-Forwarded-Proto $scheme; + proxy_pass http://127.0.0.1:8066; +} +``` + +Die vorhandenen WebSocket- und Catch-all-Locations bleiben unverändert und zeigen weiterhin direkt auf Mattermost. + +Die Exact-Match-Locations sind wichtig: Nur diese beiden Endpunkte sollen über die Bridge laufen. + +Konfiguration prüfen: + +```bash +nginx -t +``` + +Bei erfolgreicher Prüfung: + +```bash +systemctl reload nginx +``` + +## 8. Öffentliche Endpunkte testen + +### Mobile User-Agent + +```bash +curl -s -A 'Mattermost Mobile/' \ + ${MM_SITE_URL}/api/v4/config/client | + grep -o '"EnableSignUpWithOpenId":"[^"]*"' +``` + +Erwartet: + +```text +"EnableSignUpWithOpenId":"true" +``` + +### Browser User-Agent + +```bash +curl -s -A 'Mozilla/5.0' \ + ${MM_SITE_URL}/api/v4/config/client | + grep -o '"EnableSignUpWithOpenId":"[^"]*"' +``` + +Bei der dokumentierten Installation: + +```text +"EnableSignUpWithOpenId":"false" +``` + +### Mobile Login + +```bash +curl -si \ + "${MM_SITE_URL}/oauth/openid/mobile_login?redirect_to=mmauth%3A%2F%2Fcallback" | + head -20 +``` + +Erwartet wird HTTP 302 auf den Connect-Endpunkt des OIDC-Plugins. + +## 9. End-to-End-Test mit der Mattermost-App + +In der nativen Mattermost-App: + +1. Server aus `MM_SITE_URL` hinzufügen (im dokumentierten Beispiel `https://mm.nd.digital`). +2. Die App muss zusätzlich zur normalen Anmeldung einen Button **Log in with OIDC** anzeigen. +3. OIDC-Login auswählen. +4. Bei Keycloak anmelden. +5. Nach erfolgreicher Authentifizierung muss die App über `mmauth://callback` zurückkehren. +6. Team und Channels müssen anschließend geladen werden. + +## 10. Wichtiger Sonderfall: Default Team und erlaubte E-Mail-Domains + +Das `mattermost-oidc`-Plugin kann neu angelegte OIDC-Benutzer automatisch einem **Default Team** hinzufügen. + +In der dokumentierten Installation ist im Plugin konfiguriert: + +```text +Default Team: nd +``` + +Das Team `nd` erlaubt jedoch nur Benutzer mit einer bestimmten E-Mail-Domain: + +```text +nd-online.de +``` + +Beim Test wurde ein OIDC-Benutzer mit einer anderen Domain erfolgreich angelegt und authentifiziert, konnte aber nicht automatisch dem Team `nd` hinzugefügt werden. Mattermost protokollierte sinngemäß: + +```text +Failed to add user to default team +The user cannot be added as the domain associated with the account is not permitted. +``` + +Das Fehlerbild in der Mobile-App war: + +```text +Konnte nicht geladen werden +``` + +Das Profil des angemeldeten Benutzers war trotzdem erreichbar. Ursache war **nicht die Mobile Bridge und nicht der OIDC-Token**, sondern die fehlende Team-Mitgliedschaft. + +### Diagnose + +Team-Domain aus PostgreSQL nur lesend prüfen: + +```bash +su - postgres -c \ + "psql -d mattermost -c \"SELECT name, displayname, type, allowopeninvite, alloweddomains FROM teams WHERE name='nd';\"" +``` + +Alternativ in der System Console: + +```text +User Management + -> Teams + -> ND + -> Team Management + -> Only specific email domains can join this team +``` + +Wenn ein Testbenutzer aus einer anderen Domain verwendet wird, sollte die Domain-Beschränkung **nicht dauerhaft aufgeweicht** werden. + +Für den dokumentierten Test wurde die zusätzliche Testdomain kurzzeitig in der kommagetrennten Domainliste zugelassen, der Testbenutzer administrativ zum Team hinzugefügt und die Domainliste anschließend wieder auf den ursprünglichen Wert zurückgesetzt. + +## 11. Logs und Fehlersuche + +### Bridge + +Status: + +```bash +systemctl status mattermost-oidc-mobile-bridge.service +``` + +Journal: + +```bash +journalctl -u mattermost-oidc-mobile-bridge.service +``` + +Für eine gezielte Fehlersuche kann die Bridge mit `DEBUG=1` betrieben werden. Dies sollte nur bei Bedarf aktiviert werden, da dann beobachtete User-Agents protokolliert werden. + +### Mattermost + +```bash +journalctl -u mattermost.service +``` + +Bei OIDC-Problemen insbesondere nach Meldungen mit folgenden Begriffen suchen: + +```text +oidc +mobile +session +mattermost-oidc +``` + +### Typische Fehlerbilder + +**Kein OIDC-Button in der App** + +Prüfen: + +- `mattermost-oidc` ist aktiviert. +- Web-OIDC funktioniert. +- `/api/v4/config/client` wird für Mobile User-Agents über die Bridge geleitet. +- `EnableSignUpWithOpenId` ist für `Mattermost Mobile/` auf `true`. +- nginx wurde nach der Änderung erfolgreich neu geladen. + +**OIDC-Button erscheint, Login startet nicht korrekt** + +Prüfen: + +- `/oauth/openid/mobile_login` liefert HTTP 302. +- Ziel ist `/plugins/mattermost-oidc/oauth2/connect`. +- nginx routet exakt diesen Endpunkt auf Port 8066. + +**Login bei Keycloak erfolgreich, App lädt aber kein Team** + +Prüfen: + +- Wurde der Benutzer in Mattermost angelegt? +- Ist der Benutzer Mitglied eines Teams? +- Ist im OIDC-Plugin ein `Default Team` konfiguriert? +- Verhindert `AllowedDomains` des Teams das automatische Hinzufügen? + +## 12. Umgebungsvariablen der Bridge + +Die Bridge unterstützt laut Projekt-README folgende Variablen: + +| Variable | Standard | Zweck | +|---|---|---| +| `LISTEN` | `:8066` | Listen-Adresse | +| `UPSTREAM` | `http://127.0.0.1:8065` | Mattermost-Upstream | +| `PLUGIN_CONNECT_PATH` | `/plugins/mattermost-oidc/oauth2/connect` | Connect-Endpunkt des Plugins | +| `PLUGIN_CONFIG_PATH` | `/plugins/mattermost-oidc/api/v1/config` | öffentliche Plugin-Konfiguration | +| `MOBILE_UA_MATCH` | `Mattermost Mobile/` | Erkennung der nativen App | +| `OPENID_BUTTON_TEXT` | leer / automatisch | optionaler fester Button-Text | +| `OPENID_BUTTON_COLOR` | leer / automatisch | optionale feste Button-Farbe | +| `DEBUG` | leer | bei `1` User-Agent-Logging | + +In der dokumentierten Installation werden nur `LISTEN` und `UPSTREAM` explizit gesetzt. Die übrigen Werte bleiben auf den Defaults. + +## 13. Update der Bridge + +Für ein Update wird die neue Version zunächst im Variablenblock als `MM_OIDC_VER` gesetzt. `MM_OIDC_SRC` und `MM_BRIDGE_BIN` ergeben sich daraus automatisch. Die bisherige versionsbezogene Binary bleibt zunächst erhalten. + +Beispiel: Variablenblock mit der gewünschten neuen Version erneut setzen und anschließend den Release wie in Abschnitt 1 herunterladen. Danach: + +```bash +cd "$MM_OIDC_SRC/mobile-bridge" +go build -o mobile-bridge . +``` + +Neue versionsbezogene Binary installieren: + +```bash +install -o root -g root -m 755 \ + mobile-bridge \ + "$MM_BRIDGE_BIN" +``` + +Vor dem Umschalten kontrollieren: + +```bash +file "$MM_BRIDGE_BIN" +ls -lh "$MM_BRIDGE_BIN" +``` + +Symlink atomar auf die neue Version umstellen und Dienst neu starten: + +```bash +ln -sfn "$(basename "$MM_BRIDGE_BIN")" "$MM_BRIDGE_LINK" +systemctl restart mattermost-oidc-mobile-bridge.service +systemctl is-active mattermost-oidc-mobile-bridge.service +readlink -f "$MM_BRIDGE_LINK" +``` + +Danach die HTTP-Tests und einen Mobile-Login erneut durchführen. Die alte versionsbezogene Binary sollte erst entfernt werden, wenn der neue Stand erfolgreich getestet wurde. + +## 14. Rollback + +Soll die Bridge wieder entfernt werden: + +1. Die beiden Exact-Match-`location`-Blöcke aus nginx entfernen. +2. `nginx -t` ausführen. +3. nginx neu laden. +4. Bridge stoppen und deaktivieren. +5. Optional Unit-Datei und Binary entfernen. + +### Rollback auf eine vorherige Bridge-Version + +Solange die vorherige versionsbezogene Binary noch vorhanden ist, genügt es, den Symlink zurückzusetzen und den Dienst neu zu starten. Beispiel: + +```bash +ln -sfn mattermost-oidc-mobile-bridge- \ + /usr/local/sbin/mattermost-oidc-mobile-bridge +systemctl restart mattermost-oidc-mobile-bridge.service +readlink -f /usr/local/sbin/mattermost-oidc-mobile-bridge +``` + +### Bridge vollständig entfernen + +```bash +systemctl disable --now mattermost-oidc-mobile-bridge.service +rm -f /etc/systemd/system/mattermost-oidc-mobile-bridge.service +systemctl daemon-reload +rm -f /usr/local/sbin/mattermost-oidc-mobile-bridge +# Versionsbezogene Binaries bei Bedarf anschließend gezielt entfernen. +``` + +Das `mattermost-oidc`-Plugin und der normale Web-OIDC-Login können dabei unverändert weiterbetrieben werden. + +## 15. Sicherheitsaspekte + +- Die Bridge nur auf `127.0.0.1:8066` binden. +- Port 8066 nicht öffentlich in der Firewall freigeben. +- Nur die beiden benötigten Exact-Match-Endpunkte über nginx zur Bridge leiten. +- Keine OIDC-Secrets in die systemd-Unit eintragen; die Bridge benötigt keine. +- Client Secret und andere Zugangsdaten nicht in Dokumentationen oder Logs übernehmen. +- Nach Änderungen an OIDC immer Web- und Mobile-Login testen. +- Team-Domain-Beschränkungen nicht nur für einen Test dauerhaft erweitern. + +## 16. Abschlusskontrolle + +Nach einer vollständigen Installation sollten folgende Prüfungen erfolgreich sein: + +```bash +systemctl is-enabled mattermost-oidc-mobile-bridge.service +systemctl is-active mattermost-oidc-mobile-bridge.service +ss -lntp | grep ':8066' +nginx -t +``` + +Zusätzlich: + +```text +Mobile UA -> EnableSignUpWithOpenId=true +Browser UA -> unveränderte Mattermost-Konfiguration +mobile_login -> HTTP 302 zum mattermost-oidc-Plugin +Web-OIDC -> funktioniert +Mobile-OIDC -> funktioniert +Team/Channels -> werden in der App geladen +``` +