apolloconfig/apollo · error · AccessDeniedException
App admin permission is required
Error message
App admin permission is required
What it means
Thrown by ClusterController.requireDeleteClusterPermission in the CONSUMER branch when an OpenAPI consumer token attempts to delete a cluster but does not have app-admin permission on the target app. Apollo allows CONSUMER (app-scoped token) deletion only if the token's associated role grants app-admin via isAppAdmin(appId), which is isSuperAdmin() || hasAssignRolePermission(appId). Maps to HTTP 403 AccessDeniedException.
Source
Thrown at apollo-portal/src/main/java/com/ctrip/framework/apollo/openapi/v1/controller/ClusterController.java:120
}
private void requireDeleteClusterPermission(String appId) {
String authType = UserIdentityContextHolder.getAuthType();
if (UserIdentityConstants.USER.equals(authType)) {
// Keep Portal UI behavior aligned with the legacy WebAPI delete path, which required
// super-admin permission for cluster deletion.
if (unifiedPermissionValidator.isSuperAdmin()) {
return;
}
throw new AccessDeniedException("Super admin permission is required");
}
if (UserIdentityConstants.CONSUMER.equals(authType)) {
// Existing OpenAPI consumers use app-scoped authorization here. Preserve that public
// token boundary while keeping the Portal USER path compatible with the legacy WebAPI.
if (unifiedPermissionValidator.isAppAdmin(appId)) {
return;
}
throw new AccessDeniedException("App admin permission is required");
}
if (UserIdentityConstants.USER_TOKEN.equals(authType)) {
if (unifiedPermissionValidator.isSuperAdmin()) {
return;
}
throw new AccessDeniedException("Super admin permission is required");
}
throw new AccessDeniedException("Access is denied");
}
private void requireReadApplicationPermissionForUserToken(String appId) {
if (UserIdentityConstants.USER_TOKEN.equals(UserIdentityContextHolder.getAuthType())
&& !unifiedPermissionValidator.hasReadApplicationPermission(appId)) {
throw new AccessDeniedException("Access is denied");
}
}
private void requireCreateClusterPermissionForUserToken(String appId, String env,View on GitHub (pinned to d95fc18d11)
Solutions
- Grant the CONSUMER token's associated role app-admin permission (assign-role) on the target appId via the Portal's permission management page.
- Use a super-admin-level token or a USER_TOKEN with system:admin scope for cluster deletion operations.
- If the deletion is a one-time operation, have a super admin perform it interactively through the Portal.
Defensive patterns
Strategy: validation
Validate before calling
// Before delete-cluster with CONSUMER token, verify app-admin permission
// Check via the Portal permission API whether the token's role has assign-role permission
if (!consumerTokenHasAppAdmin(appId)) {
throw new IllegalStateException(
"Consumer token lacks app-admin permission on " + appId + ". Grant assign-role to proceed.");
} Try / catch
try {
client.delete("/openapi/v1/envs/" + env + "/apps/" + appId + "/clusters/" + clusterName);
} catch (AccessDeniedException e) {
logger.error("Consumer token not app-admin for appId={}. Grant app-admin role.", appId);
throw e;
} Prevention
- When provisioning CONSUMER tokens for cluster management, grant app-admin (assign-role) permission.
- Document which tokens have app-admin vs namespace-level permissions.
- Use role naming conventions that make permission scope obvious (e.g. 'appA-admin', 'appA-release-only').
When it happens
Trigger: DELETE /openapi/v1/envs/{env}/apps/{appId}/clusters/{clusterName} called with a CONSUMER token (traditional OpenAPI consumer auth) that has only read or release permissions but not app-admin on that appId.
Common situations: A CI/CD pipeline consumer token was granted namespace-level permissions (config:modify, config:release) but not the assign-role/app-admin permission needed for cluster deletion. The token can read and release configs but cannot delete clusters.
Related errors
- Super admin permission is required
- Create cluster permission is required
- Access is denied
- Metadata read permission is required
- Access is denied
AI-assisted analysis of apolloconfig/apollo@d95fc18d11 (2026-08-14).
Data as JSON: /api/errors/0b7800f269072eb4.
Report an issue: GitHub.