Microsoft Entra ID
Read the Identity overview first to understand the
IdentityProvider resource, userInfoPrefix, and claim mappings.
Configure Microsoft Entra ID (formerly Azure AD) as a Hub identity provider, either for OIDC login alone or with directory sync through Microsoft Graph.
Prerequisites
- An Entra ID tenant with an app registration.
- Admin access to grant API permissions and admin consent.
hub-corewith network access tologin.microsoftonline.comandgraph.microsoft.com, or the equivalent sovereign-cloud endpoints.
Set up the app registration
In the Azure Portal, go to Entra ID > App registrations and either create a new registration or select an existing one. Record:
| Value | Where to find it |
|---|---|
| Tenant ID | Overview → Directory (tenant) ID |
| Client ID | Overview → Application (client) ID |
| Client Secret | Certificates & secrets → New client secret |
Under Authentication > Platform configurations, add a Web platform with
your Hub deployment's redirect URI, https://<hub-url>/oidc/callback.
Then, under Token configuration > Add groups claim, choose which group
types to include — usually Security groups — and emit Group ID so groups
arrive as object IDs. Without this, tokens carry no groups claim at all.
A user in more than 200 groups exceeds what Entra ID will put in a JWT. It
responds by dropping the groups claim entirely and substituting
_claim_names and _claim_sources pointers, which Hub doesn't follow — so
those users sign in with no groups. Either scope narrow security groups to
Hub, or configure the directory below, which reads groups from Graph and isn't
subject to the limit. See ID token claims
reference for reference.
Configure OIDC login
apiVersion: authentication.hub.upbound.io/v1beta1
kind: IdentityProvider
metadata:
name: entra
spec:
redirect:
browserLogin: true
clientSecret: "<client-secret>"
scopes:
- openid
- email
- profile
validation:
userInfoPrefix: "entra:"
issuer:
# The /v2.0 suffix is required; Hub expects the v2.0 token format.
url: https://login.microsoftonline.com/<tenant-id>/v2.0
audiences:
- <client-id>
claimMappings:
username:
claim: preferred_username
groups:
claim: groups
preferred_username carries the user principal name, typically the email
address. Use email instead if you'd rather depend on the email scope, or
sub — the object ID — when UPNs may change under you, at the cost of
unreadable usernames in role bindings. In v2.0 tokens oid is equivalent to
sub; prefer sub.
Set up directory access
Skip this if you only need login. Directory queries reuse the same app registration, but need application permissions of their own. Under API permissions, add these as Application permissions, not Delegated:
| Permission | Purpose |
|---|---|
Group.Read.All | Search and list groups |
GroupMember.Read.All | List group members |
Click Grant admin consent for <tenant> afterwards. Hub authenticates with
the client credentials grant, which has no user context — application
permissions with admin consent are the only thing that works.
Configure the directory
Add a directory block alongside the login configuration:
spec:
# ...redirect and validation as above
directory:
# Entra tokens carry group object IDs — see below.
groupClaimType: DirectoryID
userClaimType: DirectoryID
config:
apiVersion: directory.hub.upbound.io/v1alpha1
kind: EntraConfiguration
tenantID: "<tenant-id>"
clientID: "<client-id>"
clientSecret: "<client-secret>"
| Field | Required | Default | Description |
|---|---|---|---|
tenantID | yes | — | Entra tenant ID (UUID). |
clientID | yes | — | Application (client) ID. |
clientSecret | yes | — | Client secret. Read back as ***; send *** on PUT to keep it, or a new value to rotate. |
graphURL | no | https://graph.microsoft.com | Microsoft Graph base URL. Override for sovereign clouds. |
loginURL | no | https://login.microsoftonline.com | Entra login endpoint. Override for sovereign clouds. |
Entra's groups claim contains object IDs, not display names, so
groupClaimType: DirectoryID is what makes directory groups and signed-in
users resolve to the same string — and why role bindings name groups as
entra:<object-id>. Switching to DisplayName also means emitting display
names in the token, under Token configuration > Add groups claim > Customize
token properties. Keep the resource named entra and userInfoPrefix set to
entra: so both sides agree — see matching directory groups to role
bindings.
Group search is a startswith prefix match on the display name. Member lists
only include users; nested groups and service principals are left out.
Sovereign clouds
For Azure Government, Azure China, or another national cloud, set both URLs on
the EntraConfiguration. The OAuth2 token scope follows graphURL
automatically.
| Cloud | graphURL | loginURL |
|---|---|---|
| Public (default) | https://graph.microsoft.com | https://login.microsoftonline.com |
| US Government (GCC High) | https://graph.microsoft.us | https://login.microsoftonline.us |
| China (21Vianet) | https://microsoftgraph.chinacloudapi.cn | https://login.chinacloudapi.cn |
Verify
# Search groups by display-name prefix.
curl -H "Authorization: Bearer $HUB_TOKEN" \
"$HUB_URL/apis/authentication.hub.upbound.io/v1beta1/groups?identityProvider=entra&displayNameQuery=Engineering"
# List members, using a group name from the response above.
curl -H "Authorization: Bearer $HUB_TOKEN" \
"$HUB_URL/apis/authentication.hub.upbound.io/v1beta1/users?identityProvider=entra&group=entra:03f0c91a-2408-4647-8d6e-f5dddbf00c58"
Troubleshooting
| Symptom | Cause | Fix |
|---|---|---|
cannot authenticate to Entra ID | Client credentials rejected. | Verify the tenant ID, client ID, and client secret, and confirm the app registration lives in that tenant. |
graph API returned 403 | Missing permissions. | Add Group.Read.All and GroupMember.Read.All as Application permissions and grant admin consent. |
directory not configured | No directory block on the IdentityProvider. | Add one. |
| Search returns nothing | displayNameQuery matches on a prefix. | Query the start of the display name, not a word in the middle. |
| Fewer members than expected | Only users are returned. | Nested groups and service principals are excluded by design; flatten the group or list the nested one separately. |
| A group is missing from a broad search | Hub returns at most 200 matches per directory query. | Narrow the query so the group falls inside the match set. |
| A signed-in user has no groups | Group overage, or no groups claim configured. | Configure the groups claim on the app registration. For users with more than 200 group memberships — Entra's JWT overage limit, unrelated to the search cap above — rely on the directory instead. |
Next step
With the provider registered, decide what its identities may do: Access management covers binding the prefixed usernames and groups above to Hub roles.