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

  1. Grant the CONSUMER token's associated role app-admin permission (assign-role) on the target appId via the Portal's permission management page.
  2. Use a super-admin-level token or a USER_TOKEN with system:admin scope for cluster deletion operations.
  3. 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 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


AI-assisted analysis of apolloconfig/apollo@d95fc18d11 (2026-08-14). Data as JSON: /api/errors/0b7800f269072eb4. Report an issue: GitHub.