You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Copy file name to clipboardExpand all lines: README.md
+69Lines changed: 69 additions & 0 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -425,6 +425,75 @@ msal-java/
425
425
-**Hardened-by-default network**: App Services run with `WEBSITE_VNET_ROUTE_ALL=1` and `WEBSITE_DNS_SERVER=168.63.129.16` so all storage traffic resolves through the `privatelink.dfs.<storage-suffix>` Private DNS zone to the Private Endpoint NIC IP.
426
426
-**Secret-less CI/CD**: GitHub Actions authenticates to Azure via OIDC federated credentials. The repo secrets (`AZURE_CLIENT_ID`, `AZURE_TENANT_ID`, `AZURE_SUBSCRIPTION_ID`) are public IDs only; there is no client secret to rotate.
427
427
428
+
## Multi-tenant App
429
+
430
+
The single-tenant `Evidence Portal SPA` registration is the one the workshop deploys by default. Alongside it, a multi-tenant counterpart — `Evidence Portal Multi-Tenant SPA` (client id `0713f130-110b-4982-9ce3-8c9227935ca0`) — has been registered in the home tenant so external Entra ID tenants can be onboarded incrementally. It may eventually replace the single-tenant app once the API and SPA are wired for multi-tenant token validation.
431
+
432
+
### Onboard a tenant
433
+
434
+
Two things must be true before users in tenant **T** can sign in:
435
+
436
+
1.**T is on the allow-list.** On the registration's *Authentication → Supported accounts* blade, *Allow only certain tenants (Preview)* is selected and T's tenant id is listed under *Allowed tenants*. The home tenant where the app is registered is always allowed implicitly.
437
+
2.**A service principal for the app exists in T.** Until a user signs in or an admin consents in T, there is no service principal there, no user/group assignment is possible, and no app role can be granted.
438
+
439
+
`devopsabcs.com` (`a34c69c7-8959-474a-9690-e98bfb0b55c6`) has already been added to the allow-list. Currently allowed tenants:
440
+
441
+
| Tenant id | Notes |
442
+
| --- | --- |
443
+
|`cddc1229-ac2a-4b97-b78a-0e5cacb5865c`| Home tenant (`MngEnvMCAP675646.onmicrosoft.com`) |
Pick the option below that matches the level of access available in the target tenant.
448
+
449
+
#### Option A — Admin consent URL (recommended)
450
+
451
+
A Global Administrator (or Privileged Role / Cloud Application Administrator) of the target tenant opens the link below **while signed into that tenant**. It instantiates the service principal and grants tenant-wide consent for any *Admin consent required* delegated scopes.
The `redirect_uri` must match a SPA redirect URI registered on the app. Drop the parameter to land on the generic Entra consent confirmation page instead.
464
+
465
+
#### Option B — User sign-in
466
+
467
+
Send a user from the target tenant to the SPA URL. Auth Code + PKCE hits `https://login.microsoftonline.com/common/oauth2/v2.0/authorize` and Entra shows the standard consent screen. If any API permission requires admin consent, the prompt is blocked until an admin completes Option A.
468
+
469
+
#### Option C — Pre-provision via Microsoft Graph
470
+
471
+
Run from a session signed in as a Global Administrator of the target tenant:
The service principal then appears under *Enterprise applications* in the target tenant. Tenant-wide consent can be granted from *Permissions → Grant admin consent*.
479
+
480
+
### After consent
481
+
482
+
Once the service principal exists in the foreign tenant, an admin in that tenant still needs to:
483
+
484
+
- Toggle *Assignment required?* under *Properties* if user/group gating is desired.
485
+
- Assign users or groups to the `CaseReader` and `CaseAdmin` app roles under *Users and groups*. App roles are defined on the home-tenant registration but assigned in each foreign tenant's enterprise application.
486
+
487
+
### What still needs to change in code to fully support multi-tenant
488
+
489
+
The registration is multi-tenant, but the SPA and API are not yet configured for it. The following changes are required before tokens issued by `devopsabcs.com` (or any other allowed tenant) will be accepted end to end:
490
+
491
+
-**SPA `auth-config.ts`**: change the `authority` from a tenant-specific `https://login.microsoftonline.com/{homeTenantId}` to `https://login.microsoftonline.com/common` (any account) or `https://login.microsoftonline.com/organizations` (work/school accounts only). A tenant-pinned authority will fail with `AADSTS50020` for users from other tenants.
492
+
-**API JWT validation** ([SecurityConfig.java](sample-app/api/src/main/java/com/example/evidence/config/SecurityConfig.java)): the issuer is currently a single tenant URL. For multi-tenant, validate against the `https://login.microsoftonline.com/common/v2.0/.well-known/openid-configuration` discovery document (which exposes the multi-tenant signing keys) and **enforce the allow-list yourself** by reading the `tid` claim and comparing it to the same set of tenant ids configured in Entra. Without that check, any tenant on the public internet that has consented could mint valid tokens.
493
+
-**API app registration**: the resource server (`Evidence API`) must also be set to *Multiple Entra ID tenants* in *Authentication → Supported accounts*, otherwise tokens with `aud=api://{apiClientId}` will not be issued for users outside the home tenant.
494
+
495
+
Until those three changes ship, the multi-tenant registration is a placeholder — it can be onboarded into other tenants for a smoke test, but `acquireTokenSilent` and the API JWT validator will reject the resulting tokens.
496
+
428
497
## Findings and Lessons Learned
429
498
430
499
These are the rough edges this codebase hit on the way to a working production deploy. Each is worth knowing before they bite you in your own environment.
0 commit comments