# OIDC setup — Microsoft Entra ID This document describes the Entra ID app-registration steps needed to make the IRDB UI's "Sign in with Microsoft" button work. Tested manually against an Entra workforce tenant; replace the example values with your own. > Polished documentation lands in M13. This file is here so M08 reviewers (and the engineer doing the manual OIDC verification step) have a reproducible path. ## 1. Register an application In the Entra admin centre (`entra.microsoft.com`): 1. **App registrations → New registration** 2. **Name**: `IRDB — UI` (any human-readable label). 3. **Supported account types**: "Accounts in this organizational directory only" is fine for the common single-tenant case. Multi-tenant only if you actually need it. 4. **Redirect URI**: pick **Web** as the platform and use the URI matching `OIDC_REDIRECT_URI` in the UI's environment, e.g. ``` http://localhost:8080/oidc/callback ``` For production: `https://reputation.example.com/oidc/callback`. 5. **Register**. Note down: - the application (client) ID → `OIDC_CLIENT_ID` - the directory (tenant) ID → used to build `OIDC_ISSUER`: ``` OIDC_ISSUER=https://login.microsoftonline.com//v2.0 ``` ## 2. Create a client secret 1. **Certificates & secrets → Client secrets → New client secret** 2. Description: `irdb-ui`. Expiry: per your org policy. 3. Copy the secret **Value** (not the Secret ID) → `OIDC_CLIENT_SECRET`. The portal hides it after you leave the page. ## 3. Configure the `groups` claim in the ID token The api decides RBAC roles from the user's group memberships, so the ID token must include a `groups` claim. 1. **Token configuration → Add groups claim**. 2. **Group types**: Security groups (or whichever type your IRDB role mappings target). 3. For each token type (ID, Access), under **Customize token properties by type**, choose **Group ID**. The api expects Entra group object IDs; emitting `sAMAccountName` or display names will not match. 4. **Save**. If your tenant has many groups assigned to the user, Entra may emit an overage indicator (`_claim_names`) instead of the raw `groups` array. In that case you'd have to call MS Graph to enumerate groups — out of scope here. For test tenants stay under the threshold (usually ~150 groups). ## 4. API permissions The default `User.Read` permission delegated to Microsoft Graph is enough to receive `openid profile email` + the `groups` claim once configured above. No additional scopes needed unless you want to call Graph elsewhere. If your tenant requires admin consent for the app, click **Grant admin consent for ** under **API permissions**. ## 5. Configure the role mappings in IRDB In the api's database, populate the `oidc_role_mappings` table: ```sql INSERT INTO oidc_role_mappings (group_id, role) VALUES ('11111111-1111-1111-1111-111111111111', 'admin'), ('22222222-2222-2222-2222-222222222222', 'operator'), ('33333333-3333-3333-3333-333333333333', 'viewer'); ``` (Group IDs are GUID/UUID strings as Entra emits them.) The admin UI for managing this lands in M10. Until then, use SQL or the seeders. `OIDC_DEFAULT_ROLE` (api env) controls behaviour for users whose groups don't match any row: - `viewer` (default) — read-only fallback. - `none` — refuse the login; the UI shows the `/no-access` page. ## 6. UI environment Fill in the matching values in `.env`: ```dotenv OIDC_ENABLED=true OIDC_ISSUER=https://login.microsoftonline.com//v2.0 OIDC_CLIENT_ID= OIDC_CLIENT_SECRET= OIDC_REDIRECT_URI=http://localhost:8080/oidc/callback # or your prod URL ``` ## 7. Test users Assign at least one test user to one of the groups you mapped. With Entra free tiers you can add guest accounts to the tenant; for paid tiers create dedicated test users. Sign them out of any browser session and walk the flow end-to-end: 1. `GET /` → `302 /login`. 2. Click **Sign in with Microsoft**. 3. Sign in to Entra; consent if prompted. 4. Land back at `/oidc/callback` → `302 /app/me`. 5. The `/app/me` page shows `role` matching the group mapping. If the user has no matching group and `OIDC_DEFAULT_ROLE=none`, the flow ends at `/no-access`. ## 8. Troubleshooting - **"AADSTS50011: redirect URI mismatch"** — the URI in the request doesn't match what's registered. The `/oidc/callback` path is case-sensitive; the host must match exactly. - **`groups` claim missing in the ID token** — re-check step 3, including selecting the claim for the **ID token** type (not just access token). Sign in again from a private window so a fresh token is issued. - **Role always `viewer`** — your group ID isn't in `oidc_role_mappings`. The api returns the default role when no row matches. - **`OIDC handshake failed: state mismatch`** — the session cookie was lost between `/login/oidc` and `/oidc/callback` (third-party-cookie blocking on cross-site flows, or session fixation reset). Confirm `SameSite=Lax` is set on the session cookie and that the redirect URI is on the same host.