{"record":{"id":"99aea5df7544f66d","repo":"apolloconfig/apollo","slug":"assign-role-permission-is-required-99aea5","errorCode":null,"errorMessage":"Assign role permission is required","messagePattern":"Assign role permission is required","errorType":"exception","errorClass":"AccessDeniedException","httpStatus":403,"severity":"error","filePath":"apollo-portal/src/main/java/com/ctrip/framework/apollo/openapi/v1/controller/PermissionController.java","lineNumber":314,"sourceCode":"  private void requirePortalUserOrAssignRolePermission(String appId) {\n    requirePortalUserOrAssignRolePermission(appId, null, null, null);\n  }\n\n  private void requirePortalUserOrAssignRolePermission(String appId, String env, String clusterName,\n      String namespaceName) {\n    String authType = UserIdentityContextHolder.getAuthType();\n    if (UserIdentityConstants.USER.equals(authType)) {\n      return;\n    }\n    if (UserIdentityConstants.CONSUMER.equals(authType)\n        && unifiedPermissionValidator.hasAssignRolePermission(appId)) {\n      return;\n    }\n    if (UserIdentityConstants.USER_TOKEN.equals(authType) && unifiedPermissionValidator\n        .hasAssignRolePermission(appId, env, clusterName, namespaceName)) {\n      return;\n    }\n    throw new AccessDeniedException(\"Assign role permission is required\");\n  }\n\n  private void requireAppRoleReadPermission(String appId) {\n    if (UserIdentityConstants.USER_TOKEN.equals(UserIdentityContextHolder.getAuthType())\n        && !unifiedPermissionValidator.hasAssignRolePermission(appId)) {\n      throw new AccessDeniedException(\"Assign role permission is required\");\n    }\n  }\n\n  private void requireAppRoleReadPermission(String appId, String env, String clusterName,\n      String namespaceName) {\n    if (UserIdentityConstants.USER_TOKEN.equals(UserIdentityContextHolder.getAuthType())\n        && !unifiedPermissionValidator.hasAssignRolePermission(appId, env, clusterName,\n            namespaceName)) {\n      throw new AccessDeniedException(\"Assign role permission is required\");\n    }\n  }\n","sourceCodeStart":296,"sourceCodeEnd":332,"githubUrl":"https://github.com/apolloconfig/apollo/blob/d95fc18d112589efc09ddcbe1507047584d55251/apollo-portal/src/main/java/com/ctrip/framework/apollo/openapi/v1/controller/PermissionController.java#L296-L332","documentation":"HTTP 403 (AccessDeniedException). Thrown by PermissionController.requirePortalUserOrAssignRolePermission when none of the allow-paths match: caller is not a plain USER, OR is a CONSUMER without app-scoped hasAssignRolePermission(appId), OR is a USER_TOKEN without namespace-scoped hasAssignRolePermission(appId,env,cluster,namespace). Used to gate role-assignment writes — assigning roles requires either being a portal user or holding the ASSIGN_ROLE permission at the right scope.","triggerScenarios":"POST role-assignment endpoints (grant/remove roles) using a CONSUMER token without ASSIGN_ROLE permission on the app, or a USER_TOKEN without namespace-scoped ASSIGN_ROLE permission.","commonSituations":"OpenAPI consumer token reused for role management it was never granted; user-token scoped to config ops attempting role assignment; permission revoked after automation was set up; attempting to assign roles on an app the token is not scoped to.","solutions":["Grant the caller ASSIGN_ROLE permission at the required scope: app-level for CONSUMER, namespace-level (appId/env/cluster/namespace) for USER_TOKEN.","Perform role assignment interactively as a portal USER (USER auth always passes this gate).","Verify the appId/env/cluster/namespace in the request match the scope of the granted ASSIGN_ROLE permission.","Pre-check hasAssignRolePermission before submitting the assignment."],"exampleFix":"// before: CONSUMER token without ASSIGN_ROLE on appX\nclient.withConsumerToken(token).assignRole(\"appX\", role); // 403\n\n// after: grant ASSIGN_ROLE (app scope) to the token, or use portal USER\nadmin.grantAssignRole(\"appX\", token);\nclient.withConsumerToken(token).assignRole(\"appX\", role);","handlingStrategy":"validation","validationCode":"// Before role assignment: confirm ASSIGN_ROLE at the right scope.\nString authType = currentAuthType();\nboolean ok;\nif (\"CONSUMER\".equals(authType))      ok = hasAssignRole(token, appId);\nelse if (\"USER_TOKEN\".equals(authType)) ok = hasAssignRole(token, appId, env, cluster, ns);\nelse                                    ok = \"USER\".equals(authType);\nif (!ok) { /* grant ASSIGN_ROLE or use portal USER; do not call assignRole */ }","typeGuard":"null","tryCatchPattern":"try {\n  client.assignRole(appId, env, cluster, ns, role);\n} catch (HttpServerErrorException.Forbidden e) {\n  // Assign role permission is required -> grant ASSIGN_ROLE at the right scope and retry\n}","preventionTips":["Grant ASSIGN_ROLE at the correct scope: app for CONSUMER, namespace for USER_TOKEN.","Perform interactive role management as a portal USER.","Pre-check hasAssignRolePermission before assigning roles."],"tags":["apollo-portal","openapi","permission","access-denied","role","assign-role","permission-controller"],"backgroundTag":null,"analyzedSha":"d95fc18d112589efc09ddcbe1507047584d55251","analyzedAt":"2026-08-14T04:00:05.477Z","schemaVersion":2},"datasetVersion":"2026-08-14T05:17:29.042Z"}