{"record":{"id":"31518dea8cf2c578","repo":"apolloconfig/apollo","slug":"access-is-denied-31518d","errorCode":null,"errorMessage":"Access is denied","messagePattern":"Access is denied","errorType":"exception","errorClass":"AccessDeniedException","httpStatus":403,"severity":"error","filePath":"apollo-portal/src/main/java/com/ctrip/framework/apollo/openapi/v1/controller/ItemController.java","lineNumber":312,"sourceCode":"      return operator;\n    }\n\n    throw new BadRequestException(\"Unsupported auth type: %s\", authType);\n  }\n\n  private boolean shouldHideConfigToPortalUser(String appId, String env, String clusterName,\n      String namespaceName) {\n    return UserIdentityConstants.USER.equals(UserIdentityContextHolder.getAuthType())\n        && unifiedPermissionValidator.shouldHideConfigToCurrentUser(appId, env, clusterName,\n            namespaceName);\n  }\n\n  private void requireConfigReadForUserToken(String appId, String env, String clusterName,\n      String namespaceName) {\n    if (UserIdentityConstants.USER_TOKEN.equals(UserIdentityContextHolder.getAuthType())\n        && unifiedPermissionValidator.shouldHideConfigToCurrentUser(appId, env, clusterName,\n            namespaceName)) {\n      throw new AccessDeniedException(\"Access is denied\");\n    }\n  }\n\n  private void requireSyncNamespacesReadableForUserToken(OpenNamespaceSyncDTO model) {\n    if (!UserIdentityConstants.USER_TOKEN.equals(UserIdentityContextHolder.getAuthType())) {\n      return;\n    }\n    for (OpenNamespaceIdentifier namespaceIdentifier : model.getSyncToNamespaces()) {\n      requireConfigReadForUserToken(namespaceIdentifier.getAppId(), namespaceIdentifier.getEnv(),\n          namespaceIdentifier.getClusterName(), namespaceIdentifier.getNamespaceName());\n    }\n  }\n\n  private OpenItemPageDTO emptyPage(Integer page, Integer size) {\n    OpenItemPageDTO result = new OpenItemPageDTO();\n    result.setPage(page);\n    result.setSize(size);\n    result.setTotal(0L);","sourceCodeStart":294,"sourceCodeEnd":330,"githubUrl":"https://github.com/apolloconfig/apollo/blob/d95fc18d112589efc09ddcbe1507047584d55251/apollo-portal/src/main/java/com/ctrip/framework/apollo/openapi/v1/controller/ItemController.java#L294-L330","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","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."],"exampleFix":null,"handlingStrategy":"validation","validationCode":"// Before item read with USER_TOKEN, verify the namespace is not hidden\nif (authType.equals(\"USER_TOKEN\") && isNamespaceHidden(appId, env, clusterName, namespaceName)) {\n    throw new SecurityException(\"Namespace is hidden from the current user. Grant edit/release permission.\");\n}","typeGuard":null,"tryCatchPattern":"try {\n    return client.get(\"/openapi/v1/envs/\" + env + \"/apps/\" + appId + \"/clusters/\" + clusterName\n        + \"/namespaces/\" + namespaceName + \"/items\");\n} catch (AccessDeniedException e) {\n    logger.warn(\"USER_TOKEN denied item read on namespace. Check namespace visibility and token scope.\");\n    throw e;\n}","preventionTips":["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."],"tags":["authorization","openapi","item","permissions","user-token","namespace-visibility","access-control","http-403"],"backgroundTag":null,"analyzedSha":"d95fc18d112589efc09ddcbe1507047584d55251","analyzedAt":"2026-08-14T04:00:05.477Z","schemaVersion":2},"datasetVersion":"2026-08-14T05:17:29.042Z"}