From 181c82d31000256eb518316249527b6ec4527571 Mon Sep 17 00:00:00 2001 From: Kawa Date: Fri, 26 Jun 2026 11:38:24 +0200 Subject: [PATCH] Document certificate (app-only) auth as primary per-profile path Co-Authored-By: Claude Opus 4.8 (1M context) --- README.md | 35 ++++++++++++++++++++++++++++++++--- 1 file changed, 32 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index 80642e8..cd174f4 100644 --- a/README.md +++ b/README.md @@ -19,7 +19,7 @@ A web admin toolbox for Microsoft 365 / SharePoint Online, built with Blazor Ser ## Configuration -Authentication uses Microsoft OIDC (interactive sign-in) and, for scheduled reports, app-only certificate auth. +Signing into the toolbox itself uses Microsoft OIDC (or a local account). Per-profile SharePoint/Graph access uses **certificate (app-only) auth** as the primary path — the same app identity drives both technician work and scheduled reports, so technicians never sign in per profile. Profiles without a certificate fall back to an interactive per-profile sign-in. Set these as environment variables (or in `appsettings.json` under the `Oidc` section). .NET maps `Section__Key` to `Section:Key`. @@ -41,8 +41,37 @@ These are separate and registered on **different** Entra apps. Don't conflate th 1. **App sign-in (OIDC).** Logging into the toolbox itself via "Sign in with Microsoft". Uses the `Oidc__*` app above. Callback path is the framework default `/signin-oidc` (not configurable here). When `App__Domain` is set, the redirect is pinned to `/signin-oidc`; otherwise it's derived from the request host (`X-Forwarded-Host`/`Host`). → On **this** app registration, add redirect URI `https://your-host/signin-oidc` under the **Web** platform. This app also needs the Graph permissions the audit/reporting features require: `GroupMember.Read.All`, `Group.Read.All`, `User.Read.All`. -2. **SharePoint connect (per-profile).** Getting a delegated SharePoint/Graph token for a client tenant. A PKCE public-client flow that uses **each connection profile's own `ClientId`/`TenantId`** — not the `Oidc__*` app. The callback for this flow is derived from `App__Domain` as `/connect/callback`; set `ClientConnect__RedirectUri` to override the full URL directly. - → On **each client-tenant profile's** app registration, add that callback value (e.g. `https://your-host/connect/callback`) under the **Mobile and desktop / public client** platform. +2. **SharePoint connect (per-profile).** Getting a SharePoint/Graph token for a client tenant. The primary path is **certificate (app-only) auth** (see below), which needs no redirect URI. Profiles without a certificate fall back to an interactive PKCE public-client flow that uses **each connection profile's own `ClientId`/`TenantId`** — not the `Oidc__*` app. That fallback's callback is derived from `App__Domain` as `/connect/callback`; set `ClientConnect__RedirectUri` to override the full URL directly. + → Only when using the interactive fallback: on **each client-tenant profile's** app registration, add that callback value (e.g. `https://your-host/connect/callback`) under the **Mobile and desktop / public client** platform. See [Per-profile app registration permissions](#per-profile-app-registration-permissions) below for the API permissions it needs. + +### Per-profile app registration permissions + +The **Register App** action in a profile provisions this registration for you (single tenant, public client) and grants org-wide admin consent automatically. The list below documents what it creates, for manual registration or auditing. + +Per-profile access uses **certificate (app-only) auth** as the primary path: the app identity drives both interactive technician work and unattended features (scheduled reports, tenant-wide audits), so technicians never sign in per profile. The cert is provisioned alongside the registration and attached as a sign-in credential. The registration grants **application permissions** for that app-only auth; it also keeps **delegated scopes** for the interactive connect flow that profiles *without* a certificate fall back to. + +**Application permissions** (app-only certificate auth — primary): + +| API | Permission | Used for | +|-----|------------|----------| +| Microsoft Graph | `User.Read.All` | Look up users (unattended) | +| Microsoft Graph | `Group.ReadWrite.All` | Read group members; add members/owners (unattended) | +| Microsoft Graph | `Directory.Read.All` | Expand M365/AAD group membership in the user-access audit | +| Microsoft Graph | `Sites.FullControl.All` | Site operations (unattended) | +| Microsoft Graph | `Mail.Send` | Send emailed scheduled reports | +| SharePoint | `Sites.FullControl.All` | App-only CSOM | + +**Delegated permissions** (interactive connect flow — only for profiles without a certificate): + +| API | Permission | Used for | +|-----|------------|----------| +| Microsoft Graph | `User.Read` | Signed-in user's basic profile | +| Microsoft Graph | `User.Read.All` | Look up users by email/UPN | +| Microsoft Graph | `Group.ReadWrite.All` | Read group members; add members/owners | +| Microsoft Graph | `Sites.Read.All` | Resolve a site's `groupId` from its `siteId` | +| SharePoint | `AllSites.FullControl` | CSOM — site permissions, content, admin operations | + +All permissions above require **admin consent**. > **HTTPS note.** The sign-in app is a confidential (Web) client, so Entra requires its `/signin-oidc` redirect URI to be **HTTPS** — plain HTTP is allowed only for `http://localhost`, not a LAN host/IP. To run OIDC on a plain-HTTP LAN deployment, put the app behind an HTTPS-terminating reverse proxy: register `https://your-host/signin-oidc`, and the app honours `X-Forwarded-Proto` (see `UseForwardedHeaders`) to build the correct `https` redirect. Without a proxy, OIDC sign-in won't work over a non-localhost HTTP host — use the local email/password login instead.