apolloconfig/apollo · error · AccessDeniedException
Access is denied
Error message
Access is denied
What it means
Thrown by ItemController.requireConfigReadForUserToken when a USER_TOKEN identity attempts to read items/config for a namespace that is hidden from the current user. The shouldHideConfigToCurrentUser check evaluates the token holder's role against namespace visibility rules. Maps to HTTP 403 AccessDeniedException.
Source
Thrown at apollo-portal/src/main/java/com/ctrip/framework/apollo/openapi/v1/controller/ItemController.java:312
return operator;
}
throw new BadRequestException("Unsupported auth type: %s", authType);
}
private boolean shouldHideConfigToPortalUser(String appId, String env, String clusterName,
String namespaceName) {
return UserIdentityConstants.USER.equals(UserIdentityContextHolder.getAuthType())
&& unifiedPermissionValidator.shouldHideConfigToCurrentUser(appId, env, clusterName,
namespaceName);
}
private void requireConfigReadForUserToken(String appId, String env, String clusterName,
String namespaceName) {
if (UserIdentityConstants.USER_TOKEN.equals(UserIdentityContextHolder.getAuthType())
&& unifiedPermissionValidator.shouldHideConfigToCurrentUser(appId, env, clusterName,
namespaceName)) {
throw new AccessDeniedException("Access is denied");
}
}
private void requireSyncNamespacesReadableForUserToken(OpenNamespaceSyncDTO model) {
if (!UserIdentityConstants.USER_TOKEN.equals(UserIdentityContextHolder.getAuthType())) {
return;
}
for (OpenNamespaceIdentifier namespaceIdentifier : model.getSyncToNamespaces()) {
requireConfigReadForUserToken(namespaceIdentifier.getAppId(), namespaceIdentifier.getEnv(),
namespaceIdentifier.getClusterName(), namespaceIdentifier.getNamespaceName());
}
}
private OpenItemPageDTO emptyPage(Integer page, Integer size) {
OpenItemPageDTO result = new OpenItemPageDTO();
result.setPage(page);
result.setSize(size);
result.setTotal(0L);View on GitHub (pinned to d95fc18d11)
Solutions
- Grant the token holder's account edit or release permission on the target namespace through the Portal.
- Ensure the USER_TOKEN has config:read scope and is authorized for the target appId.
- Switch to a CONSUMER token with appropriate namespace permissions for the target app.
Defensive patterns
Strategy: validation
Validate before calling
// Before item read with USER_TOKEN, verify the namespace is not hidden
if (authType.equals("USER_TOKEN") && isNamespaceHidden(appId, env, clusterName, namespaceName)) {
throw new SecurityException("Namespace is hidden from the current user. Grant edit/release permission.");
} Try / catch
try {
return client.get("/openapi/v1/envs/" + env + "/apps/" + appId + "/clusters/" + clusterName
+ "/namespaces/" + namespaceName + "/items");
} catch (AccessDeniedException e) {
logger.warn("USER_TOKEN denied item read on namespace. Check namespace visibility and token scope.");
throw e;
} Prevention
- Verify the token holder has edit or release permission on any namespace before reading its items.
- For restricted namespaces, use a dedicated token with explicit access grants.
- Remember that USER_TOKEN gets a hard 403 on hidden namespaces, while USER gets silent empty results — choose the auth type accordingly.
When it happens
Trigger: GET item-by-namespace or item-diff endpoints with a USER_TOKEN where the namespace is restricted and the token holder lacks edit/release permission. The method only throws for USER_TOKEN; interactive USER identity gets silent empty results via shouldHideConfigToPortalUser instead.
Common situations: A personal access token scoped to one app is used to read items from a namespace in another app that is hidden. A namespace is marked as restricted after the token was issued, so previously-working reads now fail with 403.
Related errors
- Access is denied
- Create cluster permission is required
- Metadata read permission is required
- Super admin permission is required
- App admin permission is required
AI-assisted analysis of apolloconfig/apollo@d95fc18d11 (2026-08-14).
Data as JSON: /api/errors/31518dea8cf2c578.
Report an issue: GitHub.