Role Levels

This page defines the shared Octopus role-level policy.

Role Matrix

Role

Level

Viewer

1

User

2

Operator

3

Engineer

4

Admin

5

Default for setting-level gates:

  • If a setting does not define level, it is treated as level: 0 (visible to all logged-in users).

Role naming and ROLE_PREFIX

By default, the token role names expected by the backend are:

octopus-viewer, octopus-user, octopus-operator, octopus-engineer, octopus-admin

Set the ROLE_PREFIX environment variable at deployment time to scope roles to a specific telescope or site:

ROLE_PREFIX

Expected role names

(empty)

octopus-viewer, octopus-admin, …

low

octopus-low-viewer, octopus-low-admin, …

mid

octopus-mid-viewer, octopus-mid-admin, …

stfc

octopus-stfc-viewer, octopus-stfc-admin, …

ROLE_PREFIX applies to both MSAL (Entra app roles) and Keycloak realm roles. The same prefix must be set on the frontend (ROLE_PREFIX in config.js / the frontend chart) so Keycloak role derivation stays in sync.

Selection rules when a user holds multiple roles:

  • Roles belonging to a different prefix are ignored — only this deployment’s prefix is matched.

  • When a user holds multiple roles under the same prefix (e.g. octopus-low-operator and octopus-low-admin), the highest level wins.

Per-provider overrides — if the role names in your IdP do not follow the octopus-<prefix>-<role> pattern, you can override individual names via MSENTRA_ROLE_* or KEYCLOAK_ROLE_* environment variables. Explicit overrides always take precedence over ROLE_PREFIX.

Semantics

  • A user can access a feature/setting only when: userRoleLevel >= requiredLevel.

  • Role names are canonicalized case-insensitively (admin, ADMIN -> Admin).

  • Unknown/invalid role names are treated as Viewer.

  • Role level must be enforced server-side for security. Frontend checks are UX only.

Backend

  • Source-of-truth mapping lives in auth/roles.py.

  • Auth session/token claims include role and role_level.

  • GraphQL authorization enforces minimum levels for sensitive operations.

  • Dynamic endpoint-defined GraphQL mutations require Engineer (level 4) or higher (role level > 3). Queries are available to any authenticated user.

  • Preference access is user-scoped by default:

    • A user can read/update only their own preferences (userId must match the authenticated user).

    • If userId belongs to someone else, the request is denied.

    • Only Admin (level 5) can read/update another user’s preferences.

Frontend

  • Frontend reads JWT claims (role, optional role_level) for UI behavior.

  • Frontend fetches canonical role levels from backend /auth/roles and uses them as the primary mapping.

  • If backend role levels are temporarily unavailable, frontend uses cached values (or built-in defaults) as fallback.

  • Widget settings UI hides fields where field.level > userRoleLevel.

  • Frontend filtering is not a security boundary.

SDK

  • Widget config fields support optional level?: number.

  • JSON-schema style widget settings can define level per property.

  • SDK schema conversion preserves level so host apps can enforce visibility.

Example

const schema = {
  type: 'object',
  properties: {
    useLiveData: {
      type: 'boolean',
      title: 'Use Live Data',
      level: 5,
      default: true
    },
    title: {
      type: 'string',
      title: 'Title',
      default: '' // implicit level 0
    }
  }
};