Spike - RBAC AuthZ - xblock endpoint: identify use cases and match with permissions
XBlock Handler Permissions Reference
This document describes the permissions required for actions handled by the cms.djangoapps.contentstore.views.block.xblock_handler view.
Actions and Required Permissions
These actions make requests to the /xblock/ endpoint handled by the cms.djangoapps.contentstore.views.block.xblock_handler view.
Course Outline (/course/:courseId)
Action | XBlock URL | Permission(s) |
|---|---|---|
Enable highlights emails |
|
|
Edit section/subsection/unit highlights |
|
|
Publish section/subsection/unit |
|
|
Configure section (visibility/date) |
|
|
Configure subsection (visibility/dates/grading/proctoring) |
|
|
Configure unit (visibility/discussion) |
|
|
Rename section/subsection/unit |
|
|
Delete section/subsection/unit |
|
|
Duplicate section/subsection/unit |
|
|
Add new section |
|
|
Paste clipboard content |
|
|
Drag-and-drop reorder sections |
|
|
Drag-and-drop reorder subsections/units |
|
|
Set video sharing option |
|
|
Course Unit (/course/:courseId/container/:blockId)
Action | XBlock URL | Permission(s) |
|---|---|---|
Rename unit title |
|
|
Publish unit |
|
|
Discard changes |
|
|
Toggle visibility (hide/show from learners) |
|
|
Settings (visibility/group access/discussion) |
|
|
Manage access (cohorts/enrollment tracks) |
|
|
Delete a component |
|
|
Duplicate a component |
|
|
Move a component to another unit |
|
|
Add new component |
|
|
Paste component from clipboard |
|
|
Drag-and-drop reorder components |
|
|
Block Editor (/course/:courseId/container/:blockId)
HTML / Problem / Video editor modal
Action | XBlock URL | Permission(s) |
|---|---|---|
Editor opens — block fields (v1 course block) |
|
|
Editor opens — get ancestors |
|
|
Save block (HTML/Problem/Video) |
|
|
Course Updates (/course/:courseId/course_info)
Action | XBlock URL | Permission(s) |
|---|---|---|
Page load (handouts) |
|
|
Save handouts |
|
|
Custom Pages (/course/:courseId/tabs)
Action | XBlock URL | Permission(s) |
|---|---|---|
View custom page (editor opens) |
|
|
Add new custom page |
|
|
Delete custom page |
|
|
Toggle page visibility |
|
|
Edit custom page content |
|
|
Authorization Implementation Guide
Decision Flow
1. Check if Usage Key is Provided
When usage_key_string is not provided, the request is for creating, duplicating, or moving blocks:
POST - Create new block or duplicate from another location
PUT - Create new block (e.g. custom pages via
static_tab)PATCH - Move block to another location
In all cases:
The request body must contain
parent_locator(destination parent)Extract the parent's usage key from
parent_locatorUse the parent's course key for permission checks
Always requires write access (these are all write operations)
2. Check Context Type
Determine if the request is in a course or library context, e.g. isinstance(usage_key, LibraryUsageLocator).
If this is a library context: Skip authz checks and use legacy permission checks (has_studio_read_access / has_studio_write_access).
3. Check if Authz is Enabled
Before applying authz permission checks, verify the feature flag is enabled for the course:
from openedx.core import toggles as core_toggles
if not core_toggles.AUTHZ_COURSE_AUTHORING_FLAG.is_enabled(course_key):
# Fall back to legacy permission checks
use_legacy_permissions()If authz is not enabled: Skip authz checks and use legacy permission checks.
4. Determine Permission by HTTP Method and Block Type
Permission depends on:
HTTP method (GET, POST, PUT, PATCH, DELETE)
Block type from the usage key
Request body content (for POST/PUT/PATCH)
Permission Mapping
GET Requests
Block Type | Permission |
|---|---|
|
|
All others |
|
DELETE Requests
Block Type | Permission |
|---|---|
|
|
All others |
|
POST/PUT/PATCH Requests
Check in this order:
course_info→courses.manage_course_updatesstatic_tab→courses.manage_pages_and_resourcesPublish field present with content changes → Determine intent:
make_publicwithout content changes →courses.publish_course_contentdiscard_changes→courses.publish_course_contentrepublishwith content changes →courses.edit_course_contentrepublishwithout content changes →courses.publish_course_content
Default →
courses.edit_course_content
Content change fields: metadata, data, children, fields, nullout, graderType, isPrereq, prereqUsageKey, prereqMinScore, prereqMinCompletion
Special Block Types
Course Info Blocks (course_info)
GET →
courses.view_course_updatesPUT/POST →
courses.manage_course_updates
Static Tab Blocks (static_tab)
POST/PUT →
courses.manage_pages_and_resourcesDELETE →
courses.manage_pages_and_resources
Regular Content Blocks
GET →
courses.view_coursePOST/PUT/PATCH (pure publish) →
courses.publish_course_contentPOST/PUT/PATCH (edit, with or without republish) →
courses.edit_course_contentDELETE →
courses.edit_course_content
Summary Table
HTTP Method | Block Type | Request Body | Permission |
|---|---|---|---|
GET |
|
| |
GET | Other |
| |
DELETE |
|
| |
DELETE | Other |
| |
POST/PUT/PATCH |
|
| |
POST/PUT/PATCH |
|
| |
POST/PUT/PATCH | Other | Pure publish |
|
POST/PUT/PATCH | Other | Edit |
|
Other XBlock related endpoints called in course authoring
Course Outline (/course/:courseId)
Action | XBlock URL | Permission(s) | View |
|---|---|---|---|
Page load |
|
|
|
Unlink downstream block from library |
|
|
|
Endpoints:
cms.djangoapps.contentstore.views.block.xblock_outline_handlercms.djangoapps.contentstore.rest_api.v2.views.downstreams.DownstreamView
Course Unit (/course/:courseId/container/:blockId)
Action | XBlock URL | Permission(s) |
|---|