oidc.md 5.0 KB

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/<tenant-id>/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:

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:

OIDC_ENABLED=true
OIDC_ISSUER=https://login.microsoftonline.com/<tenant-id>/v2.0
OIDC_CLIENT_ID=<application-client-id>
OIDC_CLIENT_SECRET=<value-from-step-2>
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/callback302 /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.