Troubleshooting access
This page assumes the model from the Access management overview and the identity concepts from the Identity overview. The debugging endpoints referenced below are explained in Filtering and self-review.
Access issues usually fall into one of six patterns. Work top to bottom; each section links out to the endpoint or resource that gives you the definitive answer.
"I'm an org admin but I can't list resources"
This is by design. org-admin does not cover realm-internal data such as
controlplanes, resources, resourcestats, resource relationships, or
metrics queries. See Realm-scoped
resources for the full list.
Fix. Grant yourself a RealmRoleBinding in the target realm:
apiVersion: authorization.hub.upbound.io/v1beta1
kind: RealmRoleBinding
metadata:
name: self-realm-admin
namespace: <realm>
spec:
roleRef:
name: realm-admin
subjects:
- kind: User
name: "<prefix>:<your-email>"
"My list is empty"
Two possibilities: no grant matches, or the underlying data isn't there.
Fix. Post a SelfSubjectAccessReview for the same verb and resource
(see inspect your grants),
then read status.decision:
Deny: no grant applies. Add the missing role binding.Filtered: readstatus.filter. It names exactly which realm and control plane subset you'd see. If that subset doesn't cover what you were listing, the grant is too narrow. Bind the subject in the realm it's missing, or give it a higher role — but note thatroleRef.nameis immutable, so raising a role means creating a replacement binding and deleting the old one, not editing the existing one. See Configure realm-level access.Allow, orFilteredwith a predicate that does cover what you were listing: the underlying data isn't there. Verify with a broader-scoped identity, or check that the control plane'shub-connectorhas synced the resources you expect.
"kubectl auth whoami shows no groups"
Hub sees no group membership from the token. That's an IdentityProvider
misconfiguration on the provider side, on the Hub side, or both. See
Verifying your identity for what a
healthy response looks like.
Fix.
- Confirm the token contains a groups claim. Copy a real access token
from the Hub UI (browser dev tools) and decode it in a JWT inspector.
Look for the claim your
IdentityProviderpoints at. - If the claim is missing, the IdP isn't emitting groups. Follow the per-provider setup: Entra ID, Amazon Cognito, Google Workspace, Keycloak, Okta.
- If the claim is present but Hub still shows no groups,
spec.validation.claimMappings.groups.claimon yourIdentityProvideris pointing at the wrong name. Patch theIdentityProviderand re-authenticate.
Re-authenticate after each change: a cached token still carries the old identity.
"I changed the user's groups in the IdP but their access didn't update"
Role bindings themselves apply immediately: Hub reads them from the database on
every request, so a new OrganizationRoleBinding or RealmRoleBinding is live
for the caller's very next request, with no new token required. Group membership
is the part that lags. The groups Hub matches bindings against are claims carried
inside the Hub token, so a change you make in the IdP stays invisible until the
caller gets a fresh token.
Fix. Get the caller a new token, then re-check.
- Browser UI. The session cookie refreshes on the next request, so reloading the page is usually enough. Signing out and back in forces it.
kubectlthrough the credential plugin. The plugin refreshes when the cached token expires. To force it now, runhub-credential-helper get-token --no-cache, or delete the cache directory (--cache-dir, orHUB_CACHE_DIR).- Machine clients using token exchange. Exchange a fresh IdP JWT for a new Hub token.
Confirm the new identity before looking anywhere else:
kubectl auth whoami # the exact username and groups Hub now sees
See Verifying your identity for how to read the full response.
If the groups are right and the binding still doesn't apply, the problem is the
names, not the timing. A subjects[].name has to match the prefixed identity
exactly — <userInfoPrefix><username-claim-value> for a User subject and
<userInfoPrefix><raw-group-value> for a Group subject. A missing prefix is the
most common cause of "the binding is there but nothing happens".
"The binding exists in Hub but hasn't reached the Space"
On Spaces-managed control planes a RealmRoleBinding isn't enforced by Hub
alone — it's projected down into each Space as an ObjectRoleBinding in the
realm's control plane group namespace. Until that projection lands, the binding
is real in Hub and invisible in the Space.
Fix. Read the binding's status; it reports the projection per Space:
kubectl get realmrolebinding <name> -n <realm> -o yaml
status:
spaces:
- name: space-east
ctpGroup: prod-east
objectRoleBinding: rrb-viewers
phase: Synced
lastSyncTime: "2026-07-31T09:14:22Z"
phase is one of:
| Phase | Means |
|---|---|
Pending | Hub has accepted the binding but projection hasn't started. |
Syncing | Projection is in flight. |
Synced | The ObjectRoleBinding exists in that Space. Access should work. |
Error | Projection failed. The binding won't take effect in that Space. |
A Space stuck outside Synced, or missing from the list entirely, points at the
connector rather than at your binding: check that the space connector is running
with Spaces integration enabled and can reach both the Hub API and the Spaces API
server.
"A resource type doesn't show up even though I have a realm role"
Realm roles project into every control plane in the realm, so a
realm-viewer should see whatever crossplane-view and
controlplane-view between them expose on every control plane in the
realm, regardless of that control plane's spec.identityProviders. If a
specific resource type is missing, the cause is upstream of your role
binding.
Fix.
- Confirm the type is in the aggregated ClusterRole the realm role
maps to. Add a
ClusterRoleinside the control plane labeledrbac.crossplane.io/aggregate-to-view: "true"(or theedit/adminvariants) to extend what the projection grants. - Confirm the connector actually synced the type. The
hub-connectorruns with--limit-to-cluster-roles(connector.sync.limitToClusterRolesin the Helm chart) and only syncs resources permitted by the union of those ClusterRoles. See the connector-side sync bound. - Post a
SelfSubjectAccessReviewforverb: liston the exact resource, namespace, and control plane — the response tells you whether the row-level filter is denying access.
If you need extra privileges beyond the aggregation projection (edit on
one API group, write access to a specific Composition), configure the
control plane's spec.identityProviders and add a matching
RoleBinding/ClusterRoleBinding inside the control plane. See Pass
Hub identities through to a control
plane.
Related resources
- Filtering and self-review — how to interpret the
SelfSubjectAccessReviewresponse. - Access management overview
- Roles reference