# Checkliste: Microsoft Entra ID — PORTA (OAuth) Operative Liste: **was in der App-Registrierung** im Ziel-Tenant (z. B. **poweron.swiss**) **konfiguriert** werden muss und **welche Gateway-Variablen/Code-Stellen** dazu passen. Hintergrund Konzept Auth- vs. Data-App: [`z-archive/concepts/OAuth-Auth-vs-Data-Connection-Konzept.md`](../z-archive/concepts/OAuth-Auth-vs-Data-Connection-Konzept.md). **Hinweis:** App-Registrierungen lassen sich nicht „in einen anderen Tenant verschieben“. Neu im Ziel-Tenant anlegen (oder bewusst Multi-Tenant), Secrets neu erzeugen, Nutzer müssen sich ggf. neu anmelden / Microsoft-Verbindungen neu verbinden. --- ## 1) Entra Admin Center — App registration [Azure Portal](https://portal.azure.com) → **Microsoft Entra ID** → **App registrations** → **New registration**. - **Name:** z. B. PowerOn PORTA. - **Supported account types:** - Nur eigener Tenant (**Single tenant**), oder - **Multitenant** — dann passt typisch `Service_MSFT_TENANT_ID = common` zum Authority `login.microsoftonline.com/common`. - Redirects werden unter **Authentication** ergänzt (nächster Abschnitt). --- ## 2) Authentication — Redirect URIs (Web) **App registration** → **Authentication** → **Platform** „Web“ → **Redirect URIs**. Pro öffentlich erreichbare Gateway-URL **drei** URIs (exakt, inkl. Schema): | URI | Env-Variable / Zweck | |-----|----------------------| | `{origin}/api/msft/auth/login/callback` | `Service_MSFT_AUTH_REDIRECT_URI` (Login) | | `{origin}/api/msft/auth/connect/callback` | `Service_MSFT_DATA_REDIRECT_URI` (User-Daten-Connection) | | `{origin}/api/msft/adminconsent/callback` | Admin-Consent-Flow (abgeleitet aus `Service_MSFT_DATA_REDIRECT_URI`, siehe `_admin_consent_redirect_uri()` in `routeSecurityMsft.py`) | > Fehlt die Admin-Consent-URI, scheitert der Flow mit `AADSTS50011: The redirect URI ... does not match` — der User sieht "Leider können wir Sie nicht anmelden". **In diesem Repo typische Origins** (jeweils alle drei URIs): - Lokal: `http://localhost:8000` - INT: `https://gateway-int.poweron.swiss` - PROD: `https://gateway-prod.poweron.swiss` - Forgejo/ALT-Prod (falls genutzt): `https://api.poweron.swiss` Implizite Flow / SPA: für dieses Gateway-Backend-Redirect-Muster **nicht** nötig (Confidential Client mit Secret). Backend-Routing: `platform-core/modules/routes/routeSecurityMsft.py` (Prefix `/api/msft`). --- ## 3) Certificates & secrets **Certificates & secrets** → **New client secret**. Wert in `Service_MSFT_AUTH_CLIENT_SECRET` und `Service_MSFT_DATA_CLIENT_SECRET` eintragen (bei **einer** App-Registrierung für beide Flows: **dieselben** Secrets — in den Envs oft identisch). Verschlüsselung siehe [`encrypt-env-secrets.md`](encrypt-env-secrets.md). --- ## 4) API permissions (Microsoft Graph — Delegated) **API permissions** → **Add a permission** → **Microsoft Graph** → **Delegated permissions**. Single Source of Truth für die Scope-Liste: `platform-core/modules/auth/oauthProviderConfig.py` → `msftAuthScopes`, `msftDataScopes` | Zweck | Graph permissions (delegated) | |-------|-------------------------------| | Login (`msftAuthScopes`) | `User.Read` | | Datenverbindung (`msftDataScopes`) | `User.Read`, `Mail.ReadWrite`, `Mail.Send`, `Files.ReadWrite.All`, `Sites.ReadWrite.All`, `Team.ReadBasic.All`, `OnlineMeetings.Read`, `Chat.ReadWrite`, `ChatMessage.Send`, `Calendars.Read`, `Contacts.Read` | Viele dieser Permissions erfordern **Administratoreinwilligung** im Tenant: **Grant admin consent for {tenant}**. Zusätzlicher Flow im Gateway: Admin-Consent-URL unter **`/api/msft/adminconsent`** mit Callback **`…/api/msft/adminconsent/callback`** (Redirect wird aus `Service_MSFT_DATA_REDIRECT_URI` abgeleitet — siehe `routeSecurityMsft.py`). Die Callback-URI muss zwingend unter den Redirect URIs in Abschnitt 2 eingetragen sein. **Multi-Tenant-Apps (TENANT_ID=`common`):** Admin Consent gilt **pro Tenant**. Ein Admin-Consent durch einen valueon.ch-Admin hat keine Wirkung für pamocreate.com-User. Jeder neue Tenant, der die App nutzt, braucht eine eigene Admin-Zustimmung — entweder durch den Tenant-Admin via `/api/msft/adminconsent` (im PowerOn-Wizard: "Admin-Zustimmung erteilen") oder durch direkten Aufruf von `https://login.microsoftonline.com/{tenant}/v2.0/adminconsent?client_id=...`. Solange das fehlt, bekommen User aus diesem Tenant beim Login den "Anforderung gesendet"-Screen. --- ## 5) Gateway — Env-Dateien anpassen | Variable | Bedeutung | |----------|-----------| | `Service_MSFT_AUTH_CLIENT_ID` | Application (client) ID für Login-Flow | | `Service_MSFT_AUTH_CLIENT_SECRET` | Client secret (verschlüsselt) | | `Service_MSFT_AUTH_REDIRECT_URI` | Muss **1:1** mit Entra Login-Redirect übereinstimmen | | `Service_MSFT_DATA_CLIENT_ID` | Application (client) ID für Connect; darf = Auth sein | | `Service_MSFT_DATA_CLIENT_SECRET` | Client secret (verschlüsselt) | | `Service_MSFT_DATA_REDIRECT_URI` | Muss **1:1** mit Entra Connect-Redirect übereinstimmen | | `Service_MSFT_TENANT_ID` | `common` (Multi-Tenant-Anmeldung) **oder** Verzeichnis-ID (GUID) des Tenants **poweron.swiss** für Single-Tenant-Authority | **Dateien (Stand Repo):** `platform-core/env-gateway-dev.env`, `env-gateway-int.env`, `env-gateway-prod.env`, `env-gateway-prod-forgejo.env`, ggf. `platform-core/.env`. Wenn neues **Frontend** oder neuer **API-Host**: - `APP_API_URL` — öffentliche Basis des Gateways. - `APP_ALLOWED_ORIGINS` — CORS für das UI. --- ## 6) Gateway — Python / Sicherheit (Referenz) | Datei | Inhalt | |-------|--------| | `platform-core/modules/auth/oauthProviderConfig.py` | `msftAuthScopes`, `msftDataScopes`, `msftDataScopesForRefresh` | | `platform-core/modules/routes/routeSecurityMsft.py` | Login, Connect, Admin-Consent; liest alle `Service_MSFT_*` | | `platform-core/modules/auth/tokenManager.py` | Refresh für Microsoft Data (`Service_MSFT_DATA_*`, `Service_MSFT_TENANT_ID`) | | `platform-core/modules/auth/csrf.py` | CSRF-Ausnahmen für `/api/msft/auth/*` und `/api/msft/adminconsent*` — bei **neuen** OAuth-Pfaden ggf. erweitern (selten) | Keine Code-Änderung nötig, solange **gleiche Routen** und **gleiche Scope-Menge** wie in `oauthProviderConfig.py` verwendet werden. --- ## 7) Smoke-Tests - [ ] Login mit Microsoft: Rückkehr ohne AADSTS50011 (Redirect mismatch) - [ ] **Verbindungen** → Microsoft connect/reconnect - [ ] Nach Tenant-Wechsel: Admin Consent im neuen Tenant ausgeführt - [ ] Je nach Feature: Mail, OneDrive/SharePoint, Teams/Chat, Kalender, Kontakte kurz testen