apolloconfig/apollo · error · AccessDeniedException

Access is denied

Error message

Access is denied

What it means

Thrown by InstanceController.checkConfigReadAllowed when a USER_TOKEN identity attempts to read instance/config data for a namespace that is hidden from the current user. The shouldHideConfigToCurrentUser check evaluates the token holder's role against the namespace's visibility rules. Maps to HTTP 403 AccessDeniedException.

Source

Thrown at apollo-portal/src/main/java/com/ctrip/framework/apollo/openapi/v1/controller/InstanceController.java:137

    }
    checkConfigReadAllowed(appId, env, clusterName, namespaceName);
    return ResponseEntity.ok(instanceService.getInstanceCountByNamespace(appId, Env.valueOf(env),
        clusterName, namespaceName));
  }

  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 checkConfigReadAllowed(String appId, String env, String clusterName,
      String namespaceName) {
    String authType = UserIdentityContextHolder.getAuthType();
    if (UserIdentityConstants.USER_TOKEN.equals(authType) && unifiedPermissionValidator
        .shouldHideConfigToCurrentUser(appId, env, clusterName, namespaceName)) {
      throw new AccessDeniedException("Access is denied");
    }
    if (UserIdentityConstants.CONSUMER.equals(authType) && !unifiedPermissionValidator
        .hasReleaseNamespacePermission(appId, env, clusterName, namespaceName)) {
      throw new AccessDeniedException("Access is denied");
    }
  }

  private ReleaseDTO findReleaseOrThrow(Env env, long releaseId) {
    ReleaseDTO release = releaseService.findReleaseById(env, releaseId);
    if (release == null) {
      throw NotFoundException.releaseNotFound(releaseId);
    }
    return release;
  }

  private void checkReleaseReadAllowed(String env, ReleaseDTO release) {
    if ((UserIdentityConstants.USER.equals(UserIdentityContextHolder.getAuthType())
        || UserIdentityConstants.USER_TOKEN.equals(UserIdentityContextHolder.getAuthType()))

View on GitHub (pinned to d95fc18d11)

Solutions

  1. Grant the token holder's account edit or release permission on the target namespace via the Portal permission management page.
  2. Use a CONSUMER token that has release-namespace permission on the target app/env/cluster/namespace.
  3. Switch to an account that is an app administrator for the target app.
Defensive patterns

Strategy: validation

Validate before calling

// Before instance 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 + "/instances");
} catch (AccessDeniedException e) {
    logger.warn("USER_TOKEN denied instance read on namespace. Check namespace visibility settings.");
    throw e;
}

Prevention

When it happens

Trigger: GET instance-by-namespace or instance-by-release endpoints with a USER_TOKEN where the namespace is configured as hidden (e.g. the token holder is not the app's admin and has no edit/release role for that namespace).

Common situations: A namespace has restricted visibility (common for production secrets), and a personal access token whose holder has read-only or no access to that namespace attempts to list its instances. The hide-config feature is designed to prevent unauthorized exposure of sensitive configuration data.

Related errors


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