Skip to content

My Apps

How each OIDC app in this lab — vCenter, ArgoCD, Rancher, and Vault — ends up with a working tile on myapps.microsoft.com, and the two ways this silently half-works if a resource is missing. All four use the same underlying pattern in terraform/azure/entra.tf; this page is the one place documenting it instead of repeating it four times.

The three things a tile actually needs

An azuread_application + client secret is enough for the app itself to authenticate users directly (e.g. a user manually navigating to the app and clicking "sign in with Microsoft"). It is not enough to show up on My Apps or be launchable from there — that needs all three of the following, confirmed the hard way on 2026-07-25 when both vCenter and Vault were missing one or more of them:

Requirement Resource What breaks without it
A service principal exists at all azuread_service_principal.<app> No tile, no assignment possible — an azuread_application alone has no directory presence a user can be assigned to. Confirmed missing entirely for Vault: the app registration and client secret existed, but no azuread_service_principal resource had ever been defined, so there was nothing to show.
homepage_url set on the application's web block azuread_application.<app> The tile itself renders, but clicking it fails with a generic Entra-side "App launch failed" error, before the browser ever reaches the app. For preferred_single_sign_on_mode = "oidc" apps, My Apps navigates to homepage_url first as the entry point into the real OIDC flow — with it unset, there's nowhere to send the browser. Confirmed for vCenter: direct navigation to vcsa.devhome.cloud worked the entire time (it never goes through My Apps' launch path), while the tile itself failed outright.
An app role assignment for the target group azuread_app_role_assignment The tile still doesn't appear, even with a service principal and homepage_url both correctly set. Tile visibility is driven by an actual assignment existing — independent of whether app_role_assignment_required gates authentication. Confirmed for Vault: adding login_url/preferred_single_sign_on_mode alone via the service principal wasn't enough; the tile only appeared after also assigning app-vault-users the built-in default access role (00000000-0000-0000-0000-000000000000).
resource "azuread_application" "vault" {
  # ...
  web {
    homepage_url  = "https://vault.devhome.cloud:8200"
    redirect_uris = [ /* ... */ ]
  }
}

resource "azuread_service_principal" "vault" {
  client_id                     = azuread_application.vault.client_id
  owners                        = [data.azuread_client_config.current.object_id]
  login_url                     = "https://vault.devhome.cloud:8200"
  preferred_single_sign_on_mode = "oidc"
  # app_role_assignment_required intentionally left unset - see Vault SSO
}

resource "azuread_app_role_assignment" "vault_ad_users" {
  app_role_id         = "00000000-0000-0000-0000-000000000000" # built-in default access role
  principal_object_id = data.azuread_group.ad_vault_users.object_id
  resource_object_id  = azuread_service_principal.vault.object_id
}

homepage_url vs the app's real sign-in URL

homepage_url doesn't need to be a special SSO-aware endpoint — for vCenter it's simply the bare hostname (https://vcsa.devhome.cloud), the exact same URL that already works when navigated to directly. The one deliberate choice worth calling out: it's the bare hostname, not a deep link like /ui/app/home, matching the convention already used for ArgoCD/Rancher's homepage_url — a bare hostname is more resilient to a future vCenter upgrade changing its internal SPA path than hardcoding one.

Recipe for adding a new app

  1. azuread_application with a web block setting both homepage_url and redirect_uris — not just the redirect URI the OIDC flow itself needs.
  2. azuread_service_principal referencing that application's client_id, with login_url (usually the same value as homepage_url) and preferred_single_sign_on_mode = "oidc".
  3. azuread_app_role_assignment granting the relevant AD-synced group (see On-Prem Active Directory) the built-in default access role (00000000-0000-0000-0000-000000000000) on that service principal — required for the tile to appear, separate from whatever app_role_assignment_required is set to for actual sign-in gating.
  4. terraform plan — if step 2 errors with A resource with the ID "..." already exists, a service principal was already created out-of-band at some point (e.g. by an earlier manual portal action). Import it rather than fighting Terraform for ownership: terraform import azuread_service_principal.<name> /servicePrincipals/<object-id> (note the provider needs the full /servicePrincipals/<id> path, not the bare object ID).
  5. Give Entra a minute to propagate, then check the tile from a real myapps.microsoft.com session — a hard refresh is usually enough; a full sign-out isn't required.