Spike - RBAC AuthZ - xblock endpoint: identify use cases and match with permissions

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)

Action

XBlock URL

Permission(s)

Enable highlights emails

POST /xblock/block-v1:...+type@course+block@course

courses.edit_course_content

Edit section/subsection/unit highlights

POST /xblock/{sectionId}

courses.edit_course_content

Publish section/subsection/unit

POST /xblock/{itemId}

courses.publish_course_content

Configure section (visibility/date)

POST /xblock/{sectionId}

courses.edit_course_content

Configure subsection (visibility/dates/grading/proctoring)

POST /xblock/{itemId}

courses.edit_course_content

Configure unit (visibility/discussion)

POST /xblock/{itemId}

courses.edit_course_content

Rename section/subsection/unit

POST /xblock/{itemId}

courses.edit_course_content

Delete section/subsection/unit

DELETE /xblock/{itemId}

courses.edit_course_content

Duplicate section/subsection/unit

POST /xblock/

courses.edit_course_content

Add new section

POST /xblock/

courses.edit_course_content

Paste clipboard content

POST /xblock/

courses.edit_course_content

Drag-and-drop reorder sections

PUT /xblock/block-v1:...+type@course+block@course

courses.edit_course_content

Drag-and-drop reorder subsections/units

PUT /xblock/{itemId}

courses.edit_course_content

Set video sharing option

POST /xblock/block-v1:...+type@course+block@course

courses.edit_course_content

Course Unit (/course/:courseId/container/:blockId)

Action

XBlock URL

Permission(s)

Action

XBlock URL

Permission(s)

Rename unit title

POST /xblock/{unitId}

courses.edit_course_content

Publish unit

POST /xblock/{unitId}

courses.publish_course_content

Discard changes

POST /xblock/{unitId}

courses.publish_course_content

Toggle visibility (hide/show from learners)

POST /xblock/{unitId}

courses.edit_course_content

Settings (visibility/group access/discussion)

POST /xblock/{unitId}

courses.edit_course_content

Manage access (cohorts/enrollment tracks)

POST /xblock/{xblockId}

courses.edit_course_content

Delete a component

DELETE /xblock/{xblockId}

courses.edit_course_content

Duplicate a component

POST /xblock/

courses.edit_course_content

Move a component to another unit

PATCH /xblock/

courses.edit_course_content

Add new component

POST /xblock/

courses.edit_course_content

Paste component from clipboard

POST /xblock/

courses.edit_course_content

Drag-and-drop reorder components

PUT /xblock/{unitId}

courses.edit_course_content

Block Editor (/course/:courseId/container/:blockId)

HTML / Problem / Video editor modal

Action

XBlock URL

Permission(s)

Action

XBlock URL

Permission(s)

Editor opens — block fields (v1 course block)

GET /xblock/{blockId}

courses.view_course

Editor opens — get ancestors

GET /xblock/{blockId}?fields=ancestorInfo

courses.view_course

Save block (HTML/Problem/Video)

POST /xblock/{blockId}

courses.edit_course_content

Course Updates (/course/:courseId/course_info)

Action

XBlock URL

Permission(s)

Action

XBlock URL

Permission(s)

Page load (handouts)

GET /xblock/block-v1:...+type@course_info+block@handouts

courses.view_course_updates

Save handouts

PUT /xblock/block-v1:...+type@course_info+block@handouts

courses.manage_course_updates

Custom Pages (/course/:courseId/tabs)

Action

XBlock URL

Permission(s)

Action

XBlock URL

Permission(s)

View custom page (editor opens)

GET /xblock/{blockId}

courses.view_course

Add new custom page

PUT /xblock/

courses.manage_pages_and_resources

Delete custom page

DELETE /xblock/{blockId}

courses.manage_pages_and_resources

Toggle page visibility

PUT /xblock/{blockId}

courses.manage_pages_and_resources

Edit custom page content

POST /xblock/{blockId}

courses.manage_pages_and_resources


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_locator

  • Use 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

Block Type

Permission

course_info

courses.view_course_updates

All others

courses.view_course

DELETE Requests

Block Type

Permission

Block Type

Permission

static_tab

courses.manage_pages_and_resources

All others

courses.edit_course_content

POST/PUT/PATCH Requests

Check in this order:

  1. course_infocourses.manage_course_updates

  2. static_tabcourses.manage_pages_and_resources

  3. Publish field present with content changes → Determine intent:

    • make_public without content changes → courses.publish_course_content

    • discard_changescourses.publish_course_content

    • republish with content changes → courses.edit_course_content

    • republish without content changes → courses.publish_course_content

  4. Defaultcourses.edit_course_content

Content change fields:
metadata, data, children, fields, nullout, graderType, isPrereq, prereqUsageKey, prereqMinScore, prereqMinCompletion

Special Block Types

Course Info Blocks (course_info)

  • GETcourses.view_course_updates

  • PUT/POSTcourses.manage_course_updates

Static Tab Blocks (static_tab)

  • POST/PUTcourses.manage_pages_and_resources

  • DELETEcourses.manage_pages_and_resources

Regular Content Blocks

  • GETcourses.view_course

  • POST/PUT/PATCH (pure publish) → courses.publish_course_content

  • POST/PUT/PATCH (edit, with or without republish) → courses.edit_course_content

  • DELETEcourses.edit_course_content

Summary Table

HTTP Method

Block Type

Request Body

Permission

HTTP Method

Block Type

Request Body

Permission

GET

course_info

  •  

courses.view_course_updates

GET

Other

  •  

courses.view_course

DELETE

static_tab

  •  

courses.manage_pages_and_resources

DELETE

Other

  •  

courses.edit_course_content

POST/PUT/PATCH

course_info

  •  

courses.manage_course_updates

POST/PUT/PATCH

static_tab

  •  

courses.manage_pages_and_resources

POST/PUT/PATCH

Other

Pure publish

courses.publish_course_content

POST/PUT/PATCH

Other

Edit

courses.edit_course_content

Other XBlock related endpoints called in course authoring

Course Outline (/course/:courseId)

Action

XBlock URL

Permission(s)

View

Action

XBlock URL

Permission(s)

View

Page load

GET /xblock/outline/{blockId}

courses.view_course

cms.djangoapps.contentstore.views.block.xblock_outline_handler

Unlink downstream block from library

DELETE /api/contentstore/v2/downstreams/{blockId}

courses.edit_course_content

cms.djangoapps.contentstore.rest_api.v2.views.downstreams.DownstreamView

Endpoints:

  • cms.djangoapps.contentstore.views.block.xblock_outline_handler

  • cms.djangoapps.contentstore.rest_api.v2.views.downstreams.DownstreamView

Course Unit (/course/:courseId/container/:blockId)

Action

XBlock URL

Permission(s)

Action

XBlock URL

Permission(s)