- Intro
- Class Api
- Functional Api
- Advanced
- Access Control
- Entity Lifecycle
- Schema Versioning
- Permissions
- OperationStack
- Metrics
- Queries & Filters
- Catalogs & Collections
- Composing Workflows
- Developers
- Legacy
Permissions
ArcGIS Hub uses a single, centralized permission system to determine access to functionality within the application.
Permissions are defined by IPermissionPolicy
objects, which represent platform business rules. These are stored in <Entity>BusinessRules.ts
modules and should not be exported from Hub.js.
For an overview of how permissions work, see the Access Control Guide.
Permission Policy Properties
- permission: Permission identifier, e.g.
hub:projects:create
- dependencies: Array of other permissions this permission depends on. This allows for hierarchies and reduces duplication. Keep these shallow—at most 3 levels deep.
- services: Services that must be online for this policy.
- authenticated: Must the user be authenticated?
- privileges: Platform-level privileges required, e.g.
portal:user:createItem
. The user must have all specified privileges. - entityOwner: Does this policy require the user to be the owner of the entity?
- entityEdit: Does this policy require the user to be able to edit the entity?
- licenses: Required Hub licenses. Specify only if the permission is limited to certain licenses.
- availability:
alpha
,beta
, orgeneral
availability. Can be overridden by passing?pe=permission:to:enable
in the URI. - environments:
devext
,qaext
,production
, etc. Can be overridden by passing?pe=permission:to:enable
in the URI. - assertions: Additional checks for custom scenarios not covered by other properties.
- entityConfigurable: Can an entity enable/disable this permission?
- releaseAfter: ISO date after which the permission is enabled (production only).
- retireAfter: ISO date after which the permission is disabled (for deprecating functionality).
- portalVersion: Numeric portal version (
2025.3
) after which the permission is enabled (for synchronizing releases with ArcGIS Online).
See the IPermissionPolicy
documentation for a full list of properties and detailed definitions.
Example Annotated Policy
// This is an example - there are many more Site permissions
export const SitesPermissionPolicies: IPermissionPolicy[] = [
{
// Top level policy
permission: "hub:site",
services: ["portal"],
// since sites are available for all license levels
// we don't need to specify any licenses
},
{
permission: "hub:site:edit",
// this permission depends on hub:site
dependencies: ["hub:site"],
// and adds a requirement that the user be
// authenticated, and have edit access to the site
authenticated: true,
entityEdit: true,
},
{
// this permission controls access to the domain editing UX
permission: "hub:site:edit:domain",
// by default, it's the same as hub:site:edit
// but by having a separate permission, the site can
// add more rules... see the next section
dependencies: ["hub:site:edit"],
// we also stipulate that it depends on the domains service
// so if that's down, we can have a gracefully degraded UX
services: ["domains"],
},
{
permission: "hub:site:workspace:followers:manager",
dependencies: ["hub:site:edit"],
assertions: [
{
property: "context:currentUser",
type: "is-group-admin",
value: "entity:followersGroupId",
},
],
},
{
// Example of a new feature...
permission: "hub:site:workspace:chat",
// that requires edit access
dependencies: ["hub:site:edit"],
// hub-premium license and is gated to alpha orgs in qaext
licenses: ["hub-premium"],
availability: ["alpha"],
environments: ["qaext"],
// this allows a site entity to turn this off
// see Entity Feature Flags below
entityConfigurable: true,
},
{
// Example of a new feature tied to an ArcGIS Online release
permission: "hub:site:discussion:mapview",
dependencies: ["hub:site:edit", "hub:release:2026R1"],
licenses: ["hub-premium"],
},
];
Entity Permission Policies
Entities can add additional gating for specific permissions. For example, a Site owner (jsmith
) may limit domain editing to themselves by adding an IEntityPermissionPolicy
to the .permissions
array.
site.permissions = [
{
permission: "hub:site:edit:domain",
collaborationType: "user",
collaborationId: "jsmith",
},
];
Entity Permission Policies are more limited than full IPermissionPolicy
objects, but cover many collaboration scenarios:
- Is the current user a member of a specified group?
- Is the current user a member of a specified org?
- Is the current user specifically granted access by name?
Entities can define multiple policies for the same permission; only one needs to pass.
site.permissions = [
{
permission: "hub:site:edit:domain",
collaborationType: "user",
collaborationId: "jsmith",
},
{
permission: "hub:site:edit:domain",
collaborationType: "user",
collaborationId: "dvader",
},
];
Entity Features
Entities can disable features (represented by permissions) by adding a key for the permission to the entity.features
hash. Only permissions with .entityConfigurable: true
are read from this hash, ensuring general business rules cannot be overridden.
site.features = {
"hub:site:workspace:chat": false,
// Only read if entityConfigurable: true on the permission policy
};
System Feature Flags
Hub.js supports system feature flags, passed into ArcGISContextManager.create(...)
as part of the options. The host application parses values from the URL.
System Feature Flags override Entity Feature flags and the availability
and environment
checks. They cannot override license checks or core platform privileges.
These are typically used to demonstrate upcoming features in customer Production orgs, even if gated to qaext
.
Feature Flags are reset when the user signs out.
System Service Flags
Permission policies can list dependent services. To test graceful degradation UX, you can simulate a service being offline using Service Flags, passed into ArcGISContextManager.create(...)
as options. These override live status information and are reset on sign out.
Feature Gating & User Opt-in/out
During development, features are often gated—accessible only with a specific URI parameter or in certain environments/availability modes (e.g., "alpha"). As release approaches, users may opt in to preview features. After general release, users may opt out for a limited time.
Defining Gating and Feature Permissions
Define both "gating" and "feature" permissions:
{
permission: "hub:gating:workspace:released",
availability: ["alpha"],
environments: ["devext", "qaext", "production"],
},
{
permission: "hub:feature:workspace",
dependencies: ["hub:gating:workspace:released"],
},
User Opt-in/Opt-out
When users can opt in, provide a UI that updates the IUserHubSettings.features
object. Initially, users are opted out by default:
{
"features": {
"workspace": false
}
}
To release the feature to all users, remove conditions from the gating permission:
{
permission: "hub:gating:workspace:released",
},
{
permission: "hub:feature:workspace",
dependencies: ["hub:gating:workspace:released"],
},
Update getDefaultUserHubSettings(...)
so the feature is opted in by default:
{
schemaVersion: 1.1,
username,
updated: new Date().getTime(),
features: {
workspace: true,
},
}
Update the UI to reflect general availability. The boolean value should remain consistent: true
means the user has the feature, false
means they do not.
Ending the Opt-out Period
When the opt-out period ends, apply a schema migration to remove the feature property from IUserHubSettings.features
. This prevents users from opting out and allows removal of legacy code.
Checking Permission Access
Permissions can be checked directly on an Entity instance via instance.checkPermission(permission)
. If you don’t have access to an Entity instance, use checkPermission(permission, context, entity?)
.
checkPermission("hub:events:create", entity, context);
//=> {permission: "hub:events:create", access: false, response: "not-group-member", checks: [...]}
site.checkPermission("hub:pages:create");
//=> {permission: "hub:pages:create", access: true, response: "group-member", checks: [...]}
Both return an IPermissionAccessResponse
. The most important property is .access
, indicating if the current user has access. Other properties provide debugging and observability into why .access
is returned, and can be used to display different messages.
For example, .result
will be granted
if access is allowed; if denied, it will be more informative.
Some key values:
- not-licensed-available: Feature is available, but user lacks a license. Opportunity to show an upgrade call-to-action.
- service-offline: Required service is offline. Application can show a general error or continue with degraded experience.
- service-not-available: Service is not available in the current environment. Useful for gating features not yet in Enterprise.
Most other values are specific to policy check failures.
result Value |
Description |
---|---|
"granted" | user has access |
"disabled-by-feature-flag" | access denied due to a flag |
"disabled-by-entity-flag" | access denied due to a flag |
"org-member" | user is member of granted org |
"not-org-member" | user is not member of granted org |
"group-member" | user is member of granted group |
"not-group-member" | user is not member of granted group |
"not-group-admin" | user is not admin member of granted group |
"is-user" | user is granted directly |
"not-owner" | user is not the owner |
"not-licensed" | user is not licensed |
"not-licensed-available" | user is not licensed, but could be |
"not-available" | permission not available in this context |
"not-granted" | user does not have permission |
"no-edit-access" | user does not have edit access |
"edit-access" | user has edit access but policy is for non-editors |
"invalid-permission" | permission is invalid |
"invalid-capability" | capability is invalid |
"privilege-required" | user does not have required privilege |
"service-offline" | service is offline |
"service-maintenance" | service is in maintenance mode |
"service-not-available" | service is not available in this environment |
"entity-required" | entity is required but not passed |
"not-authenticated" | user is not authenticated |
"not-alpha-org" | user is not in an alpha org |
"not-beta-org" | user is not in a beta org |
"property-missing" | assertion requires property but is missing from entity |
"property-not-array" | assertion requires array property |
"array-contains-invalid-value" | assertion specifies a value not be included |
"array-missing-required-value" | assertion specifies a value not be included |
"property-mismatch" | assertion values do not match |
"user-not-group-member" | user is not a member of a specified group |
"user-not-group-manager" | user is not a manager of a specified group |
"user-not-group-owner" | user is not a owner of a specified group |
"assertion-property-not-found" | assertion property was not found |
"assertion-failed" | assertion condition was not met |
"assertion-requires-numeric-values" | assertion requires numeric values |
"feature-disabled" | feature has been disabled for the entity |
"feature-enabled" | feature has been enabled for the entity |
"not-in-environment" | user is not in an allowed environment |
"no-policy-exists" | policy is not defined for this permission |
"disabled-by-feature-flag" | access denied due to a flag |
"disabled-by-entity-flag" | access denied due to a flag |
"org-member" | user is member of granted org |
"not-org-member" | user is not member of granted org |
"group-member" | user is member of granted org |
"not-group-member" | user is not member of granted group |
"not-group-admin" | user is not admin member of granted group |
"is-user" | user is granted directly |
"not-owner" | user is not the owner |
"not-licensed" | user is not licensed |
"not-licensed-available" | user is not licensed, but could be |
"not-available" | permission not available in this context |
"not-granted" | user does not have permission |
"no-edit-access" | user does not have edit access |
"edit-access" | user has edit access but policy is for non-editors |
"invalid-permission" | permission is invalid |
"invalid-capability" | capability is invalid |
"privilege-required" | user does not have required privilege |
"service-offline" | service is offline |
"service-maintenance" | service is in maintenance mode |
"service-not-available" | service is not available in this environment |
"entity-required" | entity is required but not passed |
"not-authenticated" | user is not authenticated |
"not-alpha-org" | user is not in an alpha org |
"not-beta-org" | user is not in a beta org |
"property-missing" | assertion requires property but is missing from entity |
"property-not-array" | assertion requires array property |
"array-contains-invalid-value" | assertion specifies a value not be included |
"array-missing-required-value" | assertion specifies a value not be included |
"property-mismatch" | assertion values do not match |
"user-not-group-member" | user is not a member of a specified group |
"user-not-group-manager" | user is not a manager of a specified group |
"user-not-group-owner" | user is not a owner of a specified group |
"assertion-property-not-found" | assertion property was not found |
"assertion-failed" | assertion condition was not met |
"assertion-requires-numeric-values" | assertion requires numeric values |
"feature-disabled" | feature has been disabled for the entity |
"feature-enabled" | feature has been enabled for the entity |
"not-in-environment" | user is not in an allowed environment |
"no-policy-exists"; | policy is not defined for this permission |