RBAC AuthZ for Course Authoring - Operator Release Notes
Verawood introduces a new, opt-in, RBAC-based authorization system for course authoring in Studio, powered by openedx-authz. This replaces the legacy CourseAccessRole-based permission model with a more granular, role-based system.
To set up an individual course, a specific organization, or your whole site to use the new system, you’ll need to both:
Enable the appropriate feature flag(s) AND
Run migrations
Please read on for full detail.
Enabling the Feature Flag
The feature is controlled by the Waffle flag authz.enable_course_authoring, which can be enabled at three levels of granularity. When the flag is disabled (the default), the legacy permission system remains in effect and no behavior changes.
This flag will be turned on by default in the next release, Willow, and the legacy permission system will be removed in Xylon.
Enabling for a specific course
Go to Django Admin:
/admin/waffle_utils/waffleflagcourseoverridemodel/Click "Add Waffle flag course override".
In the Waffle flag field, enter
authz.enable_course_authoring.In the Course id field, enter the course key (e.g. course-v1:OpenedX+DemoX+DemoCourse).
Set Override choice to Force On.
Mark as "Enabled"
Click Save.
To disable, edit the override for the same course with Override choice set to Force Off.
Please note: both the course and org specific waffle flags work as “overrides“ over the global waffle flag, this means that their effect will depend on the status of the global (instance-wide) flag, for example:
If the global flag is disabled or doesn’t exist, marking the course override flag as “Enabled“ and “Force On“, will enable the flag for the course specified
If the global flag is enabled, marking the course override flag as “Enabled“ and “Force Off“, will disable the flag for the course specified
If the course override flag is “Disabled“, the effective flag state for the course will follow the global flag state.
Enabling for an organization
Go to Django Admin:
/admin/waffle_utils/waffleflagorgoverridemodel/Click "Add Waffle flag org override".
In the Waffle flag field, enter
authz.enable_course_authoring.In the Org field, enter the organization short name (e.g. OpenedX).
Set Override choice to Force On.
Mark as "Enabled"
Click Save.
This enables the feature for all courses within that organization. To disable, edit the override for the same org with Override choice set to Force Off.
Enabling globally (instance-wide)
Go to Django Admin:
/admin/waffle/flag/Click "Add Flag".
In the Name field, enter
authz.enable_course_authoring.Set "Everyone" to "Yes"
Click Save.
Note: Global enablement affects all courses on the instance. If automatic migrations are not enabled (see below), you must run the migration management commands manually before or after toggling the global flag.
Migrating Permission Data
When enabling the new system, existing legacy role assignments (CourseAccessRole) must be migrated to openedx-authz. Two management commands are provided:
Forward migration (legacy → openedx-authz):
./manage.py cms authz_migrate_course_authoring --delete --course-id-list <course_key1> [course_key2 ...]
./manage.py cms authz_migrate_course_authoring --delete --org-id <org_name>Rollback migration (openedx-authz → legacy):
./manage.py cms authz_rollback_course_authoring --delete --course-id-list <course_key1> [course_key2 ...]
./manage.py cms authz_rollback_course_authoring --delete --org-id <org_name>You must provide either --course-id-list or --org-id to scope the migration; they cannot be combined, and running without either will produce an error.
Both commands also accept a --delete flag, which removes the successfully migrated role assignments from the source system after migration. Without --delete, the source records are preserved (the migration copies but does not move). When --delete is used, the command will prompt for confirmation before proceeding.
Using --delete is strongly recommended. The system expects permission data to exist in only one system at a time for a given resource. If role assignments remain in both systems, they can diverge over time and cause unintended behavior — for example, a course may continue to appear in a user's Studio course list even after their permissions have been removed in one system, because the assignment still exists in the other. Running without --delete should only be used for development and testing before performing the definitive migration.
Both operations run within a database transaction for consistency.
During rollback, roles that exist only in the new system (i.e., have no legacy equivalent) will remain in openedx-authz and are not migrated back. Warnings are logged for these cases.
Automatic Migrations (Opt-in)
An automatic migration mechanism can be enabled so that toggling the feature flag for a course or organization in Django Admin automatically triggers the corresponding data migration. This is controlled by the Django setting:
ENABLE_AUTOMATIC_AUTHZ_COURSE_AUTHORING_MIGRATION = True # Default: FalseWhen enabled:
Enabling the
authz.enable_course_authoringflag for a course/org automatically migrates legacy roles to openedx-authz.Disabling the flag automatically rolls back roles to the legacy system.
Migration status and errors are recorded in the AuthzCourseAuthoringMigrationRun model, viewable in Django Admin.
A runtime constraint prevents concurrent migrations on the same scope.
Important: Automatic migration only applies to course-level and organization-level flag changes. Global (instance-wide) flag changes do not trigger automatic migration due to performance risks on large instances. Global migrations must be performed manually using the management commands above.
This setting is disabled by default. Only enable it if you understand the implications of running data migrations on a live instance (the migration runs synchronously within the Django Admin request).
Audit Trail
Role assignment and removal operations in openedx-authz are now recorded in a RoleAssignmentAudit table, which tracks the operation type, the affected user, role, scope, and the actor who made the change. This table is registered in Django Admin for inspection. An OpenedxPublicSignal is also emitted on every role lifecycle event for downstream consumers.
Other Information
Known Caveat: Admin Console and Courses Without the Flag Enabled
The Admin Console interface will display all courses in the scope selectors when assigning roles, regardless of whether the feature flag is enabled for those courses. You can assign roles to any course through the admin, but those assignments will not take effect unless the flag is enabled for the specific course, its organization, or globally. This can lead to confusion where roles appear to be assigned but permissions are not enforced.
This limitation does not affect content libraries, which do not use the legacy permission system.