Authorization Schema Reference#
The Open edX Authorization schema, or authz schema, is a YAML configuration format for static permissions, permission categories, roles, and changes to existing roles. Applications ship schema files with their code, while site operators can contribute the same format through their deployment configuration. Deployment validates and compiles all contributions into the policy used by openedx-authz.
Use this reference when creating or reviewing an authz schema file. The examples omit fields only when the surrounding section does not need them.
Machine-readable schema#
The downloadable authz JSON Schema describes the fields, types, required values, and identifier formats for schema version 1.0. You can also browse the generated schema or view the schema source. Editors and validation tools can use it to check YAML files because JSON Schema applies to the data represented by both JSON and YAML.
The JSON Schema checks the structure of one file. The compiler also checks references across the combined schema, registered scope namespaces, available Paragon icons, and conflicts between contributions.
Complete example#
The following file defines one category, two permissions, one role, and an extension to a role defined elsewhere:
schema_version: "1.0"
priority: 100
permission_categories:
- id: course_content
display_name: Course content
description: Permissions for viewing and editing course content.
icon: Article
permissions:
- namespace: courses
name: view_course
display_name: View course
description: View course configuration and content.
category: course_content
scopes:
- course-v1
icon: Visibility
- namespace: courses
name: view_course_updates
display_name: View course updates
description: View course update posts.
category: course_content
scopes:
- course-v1
icon: Visibility
roles:
- id: course_observer
display_name: Course observer
description: Reviews a course without changing it.
scopes:
- course-v1
permissions:
- courses.view_course
- courses.view_course_updates
role_extensions:
- role: course_editor
add_permissions:
- courses.export_course
Top-level fields#
schema_version#
The version of the YAML format used by the file. Write it as a quoted major.minor value, such as "1.0". A deployment stops before changing the database when it encounters a version it cannot read.
priority#
An integer used when several files extend the same role and change the same field or permission. A higher number takes precedence. Contributions with the same priority may be combined when they agree or affect different fields, but conflicting values at the same priority fail validation.
Priority does not control the order shown in a user interface. Clients may sort roles, permissions, and categories for their own presentation.
permission_categories#
A list of category definitions used to group permissions for display and discovery. Categories do not grant access.
permissions#
A list of permission definitions. Application checks use the stable permission ID formed from each permission’s namespace and name.
roles#
A list of static role definitions. A role lists every permission assigned to it.
role_extensions#
A list of changes to static roles defined in this file or another schema contribution. An extension changes only the fields it includes and does not copy or replace the complete role.
Permission categories#
A category contains these fields:
idThe stable category identifier. It is required and uses lowercase snake case, such as
course_contentorlibrary_management. Category IDs are global and do not include a permission namespace. Applications that use the same ID contribute permissions to the same category.display_nameThe source-language name shown to users. It uses sentence case and is translated through the authz schema translation process.
descriptionA complete source-language sentence describing the group of permissions.
iconAn optional icon name exported by
@openedx/paragon/icons. The value is case-sensitive, such asArticle.
For example:
permission_categories:
- id: library_management
display_name: Library management
description: Permissions for managing content libraries.
icon: Article
Permissions#
A permission contains these fields:
namespaceThe stable product domain that owns the permission. It uses lowercase snake case, such as
coursesorcontent_libraries. The namespace does not need to match the Python package, Django app, IDA, or Tutor plugin that contributes the file. Code may move between applications without changing the permission ID.nameThe operation within the product domain. It uses lowercase snake case and normally begins with a verb, such as
view_course,export_course, ormanage_library_tags.display_nameThe source-language name shown to users. Changing it does not change the permission ID used by application checks.
descriptionA complete source-language sentence describing the access controlled by the permission.
categoryThe complete ID of a category defined in the combined schema.
scopesThe scope namespaces where the permission can apply. These values come from registered
ScopeDatatypes, such ascourse-v1,ccx-v1, orlib.iconAn optional, case-sensitive icon name exported by
@openedx/paragon/icons.
The complete permission ID joins namespace and name with a period. For example:
permissions:
- namespace: content_libraries
name: manage_library_tags
display_name: Manage library tags
description: Add, edit, and remove tags in a content library.
category: library_management
scopes:
- lib
The complete ID is content_libraries.manage_library_tags. Role definitions, role extensions, application checks, and API responses use this value.
The Casbin form act^content_libraries.manage_library_tags is an internal value and is not valid in a schema file.
Roles#
A role contains these fields:
idThe stable role identifier. It uses lowercase snake case, such as
course_admin,course_editor, orlibrary_author. Role IDs do not include a product namespace because authorization uses the role within its supported scopes.display_nameThe source-language name shown to users.
descriptionA complete source-language sentence describing what the role can do.
scopesThe scope namespaces where the role can be assigned. Every permission listed by the role must support those scopes.
permissionsA list of complete permission IDs. The compiler does not infer one permission from another, so the role lists every permission it needs.
iconAn optional, case-sensitive icon name exported by
@openedx/paragon/icons.hiddenAn optional boolean that defaults to
false. A hidden role does not appear in normal role discovery and selection interfaces. Hiding does not delete the role, remove existing assignments, or change permission checks.
For example:
roles:
- id: library_reviewer
display_name: Library reviewer
description: Reviews library content without publishing it.
scopes:
- lib
permissions:
- content_libraries.view_library
- content_libraries.view_library_team
icon: Visibility
The Casbin form role^library_reviewer is an internal value and is not valid as roles.id or in a role_extensions.role reference.
Role extensions#
A role extension contains role and at least one field to change:
roleThe complete ID of an existing static role.
add_permissionsComplete permission IDs to add to the role.
remove_permissionsComplete permission IDs to remove from the role.
display_name,description, andiconDisplay metadata to replace. Metadata fields left out of the extension keep their current values.
hiddenWhether the role appears in normal role discovery and selection interfaces.
For example, a deployment can allow course editors to export courses, remove their access to tag management, change the displayed role name, and hide the course auditor role:
schema_version: "1.0"
priority: 200
role_extensions:
- role: course_editor
add_permissions:
- courses.export_course
remove_permissions:
- courses.manage_tags
display_name: Course author
description: Creates and exports course content.
- role: course_auditor
hidden: true
An extension fails validation when its target role or a referenced permission does not exist. Adding a permission already assigned to the role or removing one the role does not have produces a warning and leaves the result unchanged.
Identifier rules#
Permission namespaces, permission names, category IDs, and role IDs use lowercase letters, numbers, and underscores, begin with a letter, and match [a-z][a-z0-9_]*. The period in a complete permission ID separates its namespace from its name and does not appear inside either part.
Valid identifiers include:
courses
view_course
courses.view_course
course_content
course_editor
The following values are invalid:
Courses.view_course # uppercase letter
courses:view_course # wrong separator
act^courses.view_course # internal Casbin namespace
course content # space
role^course_editor # internal Casbin namespace
Scope namespaces follow the spelling registered by their ScopeData type and may contain a hyphen. Do not apply the snake-case identifier rule to values such as course-v1 or ccx-v1.
Schema files in applications#
Applications can keep schema resources under an authz/schema package directory. Filenames are chosen by the application, but separating permission and role definitions makes the resources easier to maintain:
course_authoring/
└── authz/
└── schema/
├── permissions.yaml
└── roles.yaml
The application exposes the authz/schema directory through the openedx-authz schema entry point described in ADR 0019. The directory path is relative to the Python module, which keeps discovery independent of virtual-environment and container paths. The compiler loads every .yaml file in that directory.
Tutor configuration for site operators#
A site operator can provide an authz schema through a Python Tutor plugin that uses the openedx-authz-schema patch. Run tutor plugins printroot to find the local plugin directory, then create openedx_authz_overrides.py there:
from tutor import hooks
hooks.Filters.ENV_PATCHES.add_item((
"openedx-authz-schema",
"""
schema_version: "1.0"
priority: 200
role_extensions:
- role: course_editor
add_permissions:
- courses.export_course
remove_permissions:
- courses.manage_tags
display_name: Course author
description: Creates and exports course content.
- role: course_auditor
hidden: true
""",
))
Enable the plugin and save the rendered Tutor configuration:
tutor plugins enable openedx_authz_overrides
tutor config save
The next deployment validates and compiles the patch with the schema files provided by applications.
Checking the resulting permissions#
After deployment, use the existing enforcement management command to check the policy stored in the database:
tutor local run lms ./manage.py lms enforcement
The command expects a subject, complete permission ID, and scope. Assuming alice has course_editor in course-v1:OpenedX+DemoX+DemoCourse, the extension above produces these results:
alice courses.export_course course-v1:OpenedX+DemoX+DemoCourse
✓ ALLOWED: alice courses.export_course course-v1:OpenedX+DemoX+DemoCourse
alice courses.manage_tags course-v1:OpenedX+DemoX+DemoCourse
✗ DENIED: alice courses.manage_tags course-v1:OpenedX+DemoX+DemoCourse