# 01 — Authentifizierung & Session --- ## Inhaltsverzeichnis - [Login mit Passwort](#login-mit-passwort) - [Login mit Token](#login-mit-token) - [SSO / OAuth](#sso--oauth) - [Register](#registrierung) - [Session prüfen & wiederherstellen](#session-prüfen--wiederherstellen) - [Logout](#logout) - [Multi-Account / Device](#multi-account--device) - [Homeserver ermitteln](#homeserver-ermitteln) - [Flows & Login-Typen abfragen](#flows--login-typen-abfragen) --- ## Login mit Passwort ```dart await client.checkHomeserver(Uri.parse('https://matrix.example.org')); final loginResponse = await client.login( LoginType.mLoginPassword, password: 'geheimesPasswort', identifier: AuthenticationUserIdentifier(user: '@alice:example.org'), // oder nur Username (ohne Server): // identifier: AuthenticationUserIdentifier(user: 'alice'), initialDeviceDisplayName: 'Pyramid Android', ); // loginResponse.accessToken, .deviceId, .userId ``` --- ## Login mit Token ```dart await client.checkHomeserver(Uri.parse('https://matrix.example.org')); await client.login( LoginType.mLoginToken, token: 'einmaliger_login_token', initialDeviceDisplayName: 'Pyramid', ); ``` --- ## SSO / OAuth ```dart // Verfügbare Login-Flows abfragen final flows = await client.getLoginFlows(); final hasSso = flows.flows?.any((f) => f.type == AuthenticationTypes.sso) ?? false; // SSO-URL erzeugen (öffnet Browser/WebView) final redirectUri = 'io.pyramid.app://login-callback'; final ssoUrl = client.homeserver!.toString() + '/_matrix/client/v3/login/sso/redirect?redirectUrl=${Uri.encodeComponent(redirectUri)}'; // → Uri im Browser öffnen, nach Redirect den Token extrahieren // Nach Redirect mit Token einloggen await client.login( LoginType.mLoginToken, token: tokenAusRedirectUrl, initialDeviceDisplayName: 'Pyramid', ); ``` --- ## Registrierung ```dart // Homeserver-Registrierung prüfen await client.checkHomeserver(Uri.parse('https://matrix.example.org')); // UIAA-Flow starten try { await client.uiaRequestBackground( (auth) => client.register( username: 'neuernutzer', password: 'sicheresPasswort', initialDeviceDisplayName: 'Pyramid', auth: auth, ), ); } on MatrixException catch (e) { // e.error: M_USER_IN_USE, M_INVALID_USERNAME, etc. } ``` --- ## Session prüfen & wiederherstellen ```dart // Nach client.init() prüfen ob Session noch gültig ist if (client.isLogged()) { print('Eingeloggt als: ${client.userID}'); print('Homeserver: ${client.homeserver}'); print('Device ID: ${client.deviceID}'); print('Access Token: ${client.accessToken}'); } // Auf Login-State reagieren client.onLoginStateChanged.stream.listen((LoginState state) { switch (state) { case LoginState.loggedIn: // Session aktiv case LoginState.softLoggedOut: // Token abgelaufen, Re-Auth nötig case LoginState.loggedOut: // Ausgeloggt } }); ``` --- ## Logout ```dart // Nur dieses Device await client.logout(); // Alle Devices await client.logoutAll(); ``` --- ## Multi-Account / Device ```dart // Eigene Devices (Sessions) auflisten final devices = await client.getDevices(); for (final device in devices ?? []) { print('${device.deviceId}: ${device.displayName} — ${device.lastSeenIp}'); } // Device umbenennen await client.updateDevice( deviceId: 'DEVICEID', displayName: 'Pyramid (Wohnzimmer)', ); // Device löschen (andere Session killen) await client.deleteDevice( 'ANDERES_DEVICE_ID', auth: AuthenticationPassword( identifier: AuthenticationUserIdentifier(user: client.userID!), password: 'meinPasswort', ), ); // Mehrere Devices auf einmal löschen await client.deleteDevices( ['DEVICE1', 'DEVICE2'], auth: AuthenticationPassword(...), ); ``` --- ## Homeserver ermitteln ```dart // .well-known auflösen (Autodiscovery) final discovery = await client.checkHomeserver( Uri.parse('https://example.org'), // Domain reicht, SDK findet Matrix-Server ); // client.homeserver ist jetzt gesetzt // Direkt mit bekannter HS-URL await client.checkHomeserver(Uri.parse('https://matrix.example.org')); // Homeserver-Versioninfo final serverVersion = await client.getVersions(); print(serverVersion.versions); // ['v1.1', 'v1.2', ...] ``` --- ## Flows & Login-Typen abfragen ```dart final response = await client.getLoginFlows(); for (final flow in response.flows ?? []) { switch (flow.type) { case AuthenticationTypes.password: // m.login.password case AuthenticationTypes.sso: // m.login.sso case AuthenticationTypes.token: // m.login.token case 'm.login.cas': // Legacy-CAS } } // SSO-Provider Details (für Brand-Buttons im UI) final ssoProviders = response.flows ?.where((f) => f.type == AuthenticationTypes.sso) .expand((f) => f.identityProviders ?? []) .toList(); // ssoProvider.id, .name, .brand, .icon ``` --- ## UIAA (User-Interactive Auth) Flows ```dart // Generisches UIAA-Handling (z.B. für Account-Löschung) await client.uiaRequestBackground( (auth) => client.deactivateAccount(auth: auth, eraseData: false), ); // Passwort ändern (braucht Re-Auth) await client.uiaRequestBackground( (auth) => client.changePassword( 'neuesPasswort', auth: auth, oldPassword: 'altesPasswort', // optional, falls Server es erlaubt ), ); ``` --- ## Fehlerbehandlung ```dart try { await client.login(...); } on MatrixException catch (e) { switch (e.error) { case MatrixError.M_FORBIDDEN: // Falsches Passwort case MatrixError.M_USER_IN_USE: // Username vergeben case MatrixError.M_INVALID_USERNAME: case MatrixError.M_LIMIT_EXCEEDED: // Rate-Limiting case MatrixError.M_UNKNOWN: } print(e.errorMessage); // Menschenlesbarer Text vom Server } ```