openedx_authz.rest_api.v1 package#
Subpackages#
Submodules#
openedx_authz.rest_api.v1.fields module#
Fields serializer for the Open edX AuthZ REST API.
- class openedx_authz.rest_api.v1.fields.CaseSensitiveCommaSeparatedListField(*args, **kwargs)
Bases:
CharFieldSerializer for a comma-separated list of strings, case-sensitive.
- to_internal_value(data)
Convert string separated by commas to list of unique items preserving order
- to_representation(value)
Convert list to string separated by commas
- class openedx_authz.rest_api.v1.fields.CommaSeparatedListField(*args, **kwargs)
Bases:
CharFieldSerializer for a comma-separated list of strings.
- to_internal_value(data)
Convert string separated by commas to list of unique items preserving order
- to_representation(value)
Convert list to string separated by commas
- class openedx_authz.rest_api.v1.fields.LowercaseCharField(*args, **kwargs)
Bases:
CharFieldSerializer for a lowercase string.
- to_internal_value(data)
Convert string to lowercase
- to_representation(value)
Convert string to lowercase
openedx_authz.rest_api.v1.paginators module#
Pagination classes for the REST API.
- class openedx_authz.rest_api.v1.paginators.AuthZAPIViewPagination
Bases:
PageNumberPaginationPagination class for the AuthZ API views.
- max_page_size = 100
- page_size = 10
- page_size_query_param = 'page_size'
openedx_authz.rest_api.v1.permissions module#
Permissions for the Open edX AuthZ REST API.
- class openedx_authz.rest_api.v1.permissions.AnyScopePermission
Bases:
MethodPermissionMixin,BasePermissionPermission handler for endpoints that are not tied to a specific scope.
Grants access if the user has at least one of the required permissions in any scope.
- has_permission(request, view) bool
Check if the user has any of the required permissions across all scopes.
Superusers and staff are automatically granted access. For other users, grants access if the user has at least one required permission in any scope.
- Returns:
True if the user has at least one required permission in any scope.
- Return type:
- class openedx_authz.rest_api.v1.permissions.BaseScopePermission
Bases:
BasePermissionBase permission class for all scope-based permissions.
This class provides the foundation for implementing scope-based authorization checks in the REST API. It extracts scope information from requests and provides hooks for permission validation. Subclasses should override the permission methods to implement specific authorization logic for their scope types.
- NAMESPACE: ClassVar[str] = 'global'
The namespace identifier for this permission class. Default
globalfor generic scopes.
- get_scope_namespace(request) str
Derive the namespace from the request scope value.
Attempts to parse the scope value and extract its namespace. If the scope value is invalid or missing, falls back to this class’s NAMESPACE.
- Parameters:
request – The Django REST framework request object.
- Returns:
The scope namespace (e.g., ‘lib’, ‘global’).
- Return type:
Examples
>>> request.data = {"scope": "lib:DemoX:CSPROB"} >>> permission.get_scope_namespace(request) 'lib' >>> request.data = {} >>> permission.get_scope_namespace(request) 'global'
- get_scope_value(request) str | None
Extract the scope value from the request.
When a
scopeslist is provided, returns only the first element. This is intentional: bulk requests are expected to be homogeneous (all scopes must share the same namespace). Actual per-scope permission validation for bulk requests is handled inDynamicScopePermission.- Parameters:
request – The Django REST framework request object.
- Returns:
The scope value if found (e.g., ‘lib:DemoX:CSPROB’), or None if not present.
- Return type:
str | None
- has_object_permission(request, view, obj) bool
Fallback object-level permission check (deny by default).
Subclasses should override this method to implement their specific object-level permission logic.
- Returns:
False (deny access by default).
- Return type:
- class openedx_authz.rest_api.v1.permissions.ContentLibraryPermission
Bases:
MethodPermissionMixin,BaseScopePermissionPermission handler for content library scopes.
This class implements permission checks specific to content library operations. It uses the authz API to verify whether a user has the necessary permissions to perform actions on library team members.
- has_permission(request, view) bool
Check if the user has permission to perform the requested action.
First checks if the view method has @authz_permissions decorator. If present, validates all required permissions. If not present, allows access by default.
- Returns:
- True if the user has the required permission, False otherwise.
Also returns False if no scope value is provided in the request.
- Return type:
- class openedx_authz.rest_api.v1.permissions.CoursePermission
Bases:
MethodPermissionMixin,BaseScopePermissionPermission handler for course scopes.
This class implements permission checks specific to course operations. It uses the authz API to verify whether a user has the necessary permissions to perform actions on course team members or course resources.
- has_permission(request, view) bool
Check if the user has permission to perform the requested action.
First checks if the view method has @authz_permissions decorator. If present, validates all required permissions. If not present, allows access by default.
- Returns:
- True if the user has the required permission, False otherwise.
Also returns False if no scope value is provided in the request.
- Return type:
- class openedx_authz.rest_api.v1.permissions.DynamicScopePermission
Bases:
BaseScopePermissionDispatcher permission class that delegates permission checks to scope-specific handlers.
This class acts as a dispatcher that automatically selects and delegates to the appropriate permission class based on the request’s scope namespace. It also provides special handling for superusers and staff members.
- Permission Flow:
Check if user is superuser or staff (automatic approval).
Extract the scope namespace from the request.
Look up the appropriate permission class for that namespace.
Delegate the permission check to that class.
Examples
>>> permission = ScopePermission() >>> # For a library scope request, this will delegate to ContentLibraryPermission >>> request.data = {"scope": "lib:DemoX:CSPROB"} >>> ContentLibraryPermission.has_permission(request, view) >>> # For a generic scope request, this will delegate to BaseScopePermission >>> request.data = {"scope": "global:generic"} >>> BaseScopePermission.has_permission(request, view)
Note
Superusers and staff members always have permission regardless of scope. Bulk requests (
scopeslist) must be homogeneous — all scopes must share the same namespace (e.g., allcourse-v1:or alllib:). Mixed namespaces will raise aValueErrorduring namespace resolution.- has_object_permission(request, view, obj) bool
Delegate object-level permission check to the appropriate scope-specific permission class.
Superusers and staff members are automatically granted permission. For other users, the object-level permission check is delegated to the permission class registered for the request’s scope namespace.
Examples
>>> # Regular user gets scope-specific check >>> request.data = {"scope": "lib:DemoX:CSPROB"} >>> permission.has_object_permission(request, view, obj) # Delegates to ContentLibraryPermission
- has_permission(request, view) bool
Delegate permission check to the appropriate scope-specific permission class.
Superusers and staff members are automatically granted permission. For other users, the permission check is delegated to the permission class registered for the request’s scope namespace.
For bulk requests that carry a
scopeslist, delegates to_has_bulk_permission: every scope must pass at least one of the required permissions (OR logic per permission, AND logic across scopes).Examples
>>> # Regular user gets scope-specific check >>> request.data = {"scope": "lib:DemoX:CSPROB"} >>> permission.has_permission(request, view) # Delegates to ContentLibraryPermission
- class openedx_authz.rest_api.v1.permissions.MethodPermissionMixin
Bases:
objectMixin that validates permissions defined via @authz_permissions decorator.
This mixin reads the required_permissions attribute set by the @authz_permissions decorator and validates each permission using
is_user_allowed. All permissions must be satisfied for the check to pass.- Usage:
Combine this mixin with BaseScopePermission to create permission classes that use method-level permission declarations:
>>> class MyPermission(MethodPermissionMixin, BaseScopePermission): ... NAMESPACE = "lib" ... >>> class MyView(APIView): ... permission_classes = [MyPermission] ... ... @authz_permissions(["content_libraries.view_library_team"]) ... def get(self, request): ... pass
- get_required_permissions(request, view) list[str]
Extract required permissions from the view method.
- validate_permissions(request, permissions: list[str], scope_value: str) bool
Validate that the user has at least one of the required permissions for the scope.
- Parameters:
request – The Django REST framework request object.
permissions – List of permission identifiers to check (OR logic — any one suffices).
scope_value – The scope to check permissions against.
- Returns:
True if user has at least one required permission, False otherwise.
- Return type:
- class openedx_authz.rest_api.v1.permissions.PermissionMeta(name, bases, attrs)
Bases:
BasePermissionMetaclassMetaclass that automatically registers permission classes by namespace.
This metaclass maintains a registry of permission classes indexed by their NAMESPACE attribute. When a permission class is defined with a NAMESPACE, it is automatically registered in the permission_registry for later retrieval.
- classmethod get_permission_class(namespace: str) type[BaseScopePermission]
Retrieve the permission class for the given namespace.
- Parameters:
namespace – The namespace identifier (e.g., ‘lib’, ‘global’).
- Returns:
- The permission class for the namespace,
or BaseScopePermission if the namespace is not registered.
- Return type:
type[“BaseScopePermission”]
Examples
>>> PermissionMeta.get_permission_class("lib") <class 'ContentLibraryPermission'> >>> PermissionMeta.get_permission_class("unknown") <class 'BaseScopePermission'>
openedx_authz.rest_api.v1.serializers module#
Serializers for the reusable Open edX AuthZ REST API.
- class openedx_authz.rest_api.v1.serializers.ActionMixin(*args, **kwargs)
Bases:
SerializerMixin providing action field functionality.
- class openedx_authz.rest_api.v1.serializers.AddUsersToRoleWithScopeSerializer(*args, **kwargs)
Bases:
RoleScopeValidationMixin,RoleMixin,ScopeMixinSerializer for adding users to a role with one or more scopes.
Accepts either a single
scopestring (backward-compatible) or ascopeslist for bulk assignment. Exactly one of the two must be provided per request.- validate(attrs) dict
Validate that exactly one of ‘scope’/’scopes’ is provided and that every scope exists in the registry, exists in the system, and supports the role. Returns validated data with a unified
scopeslist of strings.
- class openedx_authz.rest_api.v1.serializers.ListRolesWithScopeResponseSerializer(*args, **kwargs)
Bases:
SerializerSerializer for listing roles with a scope response.
- class openedx_authz.rest_api.v1.serializers.ListRolesWithScopeSerializer(*args, **kwargs)
Bases:
SerializerSerializer for listing roles within a scope.
- validate_scope(value: str) ScopeData
Validate and convert scope string to a ScopeData instance.
Checks that the provided scope is registered in the scope registry and returns an instance of the appropriate ScopeData subclass.
- Parameters:
value – The scope string to validate (e.g., ‘lib’, ‘global’, ‘org’).
- Returns:
An instance of the appropriate ScopeData subclass for the scope.
- Return type:
ScopeData
- Raises:
serializers.ValidationError – If the scope is not registered in the scope registry.
Examples
>>> validate_scope('lib:DemoX:CSPROB') ContentLibraryData(external_key='lib:DemoX:CSPROB')
- class openedx_authz.rest_api.v1.serializers.ListUsersInRoleWithScopeResponseSerializer(*args, **kwargs)
Bases:
SerializerSerializer for listing users in a role with a scope response.
- class openedx_authz.rest_api.v1.serializers.ListUsersInRoleWithScopeSerializer(*args, **kwargs)
Bases:
ScopeMixin,OrderMixinSerializer for listing users in a role with a scope.
- class openedx_authz.rest_api.v1.serializers.OrderMixin(*args, **kwargs)
Bases:
SerializerMixin providing ordering field functionality.
- class openedx_authz.rest_api.v1.serializers.PermissionValidationResponseSerializer(*args, **kwargs)
Bases:
PermissionValidationSerializerSerializer for permission validation response.
- class openedx_authz.rest_api.v1.serializers.PermissionValidationSerializer(*args, **kwargs)
Bases:
ActionMixin,ScopeMixinSerializer for permission validation request.
The
scopeis optional: when provided, the permission is validated against that scope; when omitted, the permission is validated across any scope.
- class openedx_authz.rest_api.v1.serializers.RemoveUsersFromRoleWithScopeSerializer(*args, **kwargs)
Bases:
RoleScopeValidationMixin,RoleMixin,ScopeMixinSerializer for removing users from a role with a scope.
- class openedx_authz.rest_api.v1.serializers.RoleMixin(*args, **kwargs)
Bases:
SerializerMixin providing role field functionality.
- class openedx_authz.rest_api.v1.serializers.RoleScopeValidationMixin(*args, **kwargs)
Bases:
SerializerMixin providing role and scope validation logic.
- validate(attrs) dict
Validate that the specified role and scope are valid and that the role exists in the scope.
This method performs the following validations: 1. Validates that the scope is registered in the scope registry 2. Validates that the scope exists in the system 3. Validates that the role is defined into the roles assigned to the scope
- Parameters:
attrs – Dictionary containing ‘role’ and ‘scope’ keys with their string values.
- Returns:
The validated data dictionary with ‘role’ and ‘scope’ keys.
- Return type:
- Raises:
serializers.ValidationError – If the scope is not registered, doesn’t exist, or if the role is not defined in the scope.
- class openedx_authz.rest_api.v1.serializers.ScopeMixin(*args, **kwargs)
Bases:
SerializerMixin providing scope field functionality.
- class openedx_authz.rest_api.v1.serializers.UserRoleAssignmentSerializer(*args, **kwargs)
Bases:
SerializerSerializer for a user role assignment.
- get_email(obj) str
Get the email for the given role assignment.
- get_full_name(obj) str
Get the full name for the given role assignment.
- get_username(obj: RoleAssignmentData) str
Get the username for the given role assignment.
- class openedx_authz.rest_api.v1.serializers.UserValidationAPIViewResponseSerializer(*args, **kwargs)
Bases:
SerializerSerializer for user validation response.
- class openedx_authz.rest_api.v1.serializers.UserValidationAPIViewSerializer(*args, **kwargs)
Bases:
SerializerSerializer for validating user existence.
- class openedx_authz.rest_api.v1.serializers.UserValidationSummarySerializer(*args, **kwargs)
Bases:
SerializerSerializer for user validation summary statistics.
openedx_authz.rest_api.v1.urls module#
Open edX AuthZ API v1 URLs.
openedx_authz.rest_api.v1.views module#
REST API views for Open edX Authorization (AuthZ) system.
This module provides Django REST Framework views for managing authorization permissions, roles, and user assignments within Open edX platform.
These endpoints are generic to Authorization. Any consumer can call them as-is, with no assumptions about which application is calling.
- class openedx_authz.rest_api.v1.views.PermissionValidationMeView(**kwargs)
Bases:
APIViewAPI view for validating user permissions against authorization policies.
This view enables authenticated users to verify their permissions for specific actions and scopes within the Open edX authorization system. It supports batch validation of multiple permissions in a single request.
Endpoints
POST: Validate one or more permissions for the authenticated user
Request Format
Expects a list of permission objects, each containing:
action: The action to validate (e.g., ‘content_libraries.edit_library_content’)
scope (Optional): The authorization scope (e.g., ‘lib:DemoX:CSPROB’). When omitted, the permission is validated across any scope (the user is allowed if they have the permission in at least one scope).
Response Format
Returns a list of validation results, each containing:
action: The requested action
scope: The requested scope (only present when a scope was provided in the request)
allowed: Boolean indicating if the user has the permission
Authentication and Permissions
Requires authenticated user.
Example Request
POST /api/authz/v1/permissions/validate/me:
[ {"action": "edit_library", "scope": "lib:DemoX:CSPROB"}, {"action": "delete_library_content", "scope": "lib:OpenedX:CS50"} ]
Example Response:
[ {"action": "edit_library", "scope": "lib:DemoX:CSPROB", "allowed": true}, {"action": "delete_library_content", "scope": "lib:OpenedX:CS50", "allowed": false} ]
Example Request (without scope)
POST /api/authz/v1/permissions/validate/me:
[ {"action": "content_libraries.manage_library_team"}, {"action": "courses.manage_course_team"} ]
Example Response (without scope):
[ {"action": "content_libraries.manage_library_team", "allowed": true}, {"action": "courses.manage_course_team", "allowed": false} ]
- authentication_classes = [<class 'edx_rest_framework_extensions.auth.jwt.authentication.JwtAuthentication'>, <class 'edx_rest_framework_extensions.auth.session.authentication.SessionAuthenticationAllowInactiveUser'>]
- permission_classes = [<class 'rest_framework.permissions.IsAuthenticated'>, <class 'rest_framework.permissions.AllowAny'>]
- post(request: HttpRequest) Response
Validate one or more permissions for the authenticated user.
- class openedx_authz.rest_api.v1.views.RoleListView(**kwargs)
Bases:
APIViewAPI view for retrieving role definitions and their associated permissions within a specific scope.
This view provides read-only access to role definitions within a specific authorization scope. It returns detailed information about each role including the permissions granted and the number of users assigned to each role.
Endpoints
GET: Retrieve all roles and their permissions for a specific scope
Query Parameters
scope (Required): The scope to query roles for (e.g., ‘lib:OpenedX:CSPROB’)
page (Optional): Page number for pagination
page_size (Optional): Number of items per page
Response Format
Returns a paginated list of role objects, each containing:
role: The role’s external identifier (e.g., ‘library_author’, ‘library_user’)
permissions: List of permission identifiers granted by this role (e.g., ‘content_libraries.delete_library’)
user_count: Number of users currently assigned to this role
Authentication and Permissions
Requires authenticated user.
Requires
manage_library_teampermission for the scope.
Example Request
GET /api/authz/v1/roles/?scope=lib:OpenedX:CSPROB&page=1&page_size=10
Example Response:
{ "count": 2, "next": null, "previous": null, "results": [ { "role": "library_author", "permissions": ["delete_library_content", "edit_library"], "user_count": 5 }, { "role": "library_user", "permissions": ["view_library", "view_library_team", "reuse_library_content"], "user_count": 12 } ] }
- authentication_classes = [<class 'edx_rest_framework_extensions.auth.jwt.authentication.JwtAuthentication'>, <class 'edx_rest_framework_extensions.auth.session.authentication.SessionAuthenticationAllowInactiveUser'>]
- get(request: HttpRequest) Response
Retrieve all roles and their permissions for a specific scope.
- pagination_class
alias of
AuthZAPIViewPagination
- permission_classes = [<class 'rest_framework.permissions.IsAuthenticated'>, <class 'openedx_authz.rest_api.v1.permissions.DynamicScopePermission'>]
- class openedx_authz.rest_api.v1.views.RoleUserAPIView(**kwargs)
Bases:
APIViewAPI view for managing user-role assignments within specific authorization scopes.
This view provides comprehensive role management capabilities, allowing administrators to view, assign, and remove role assignments for users within a given scope. It supports bulk operations for adding and removing multiple users, along with filtering, searching, sorting, and pagination of results.
Endpoints
GET: Retrieve all users with their role assignments in a scope
PUT: Assign multiple users to a specific role within a scope
DELETE: Remove multiple users from a specific role within a scope
Query Parameters (GET)
scope (Required): The authorization scope to query (e.g., ‘lib:DemoX:CSPROB’)
search (Optional): Search term to filter users by username, email or full name
roles (Optional): Filter by comma-separated list of specific role names
page (Optional): Page number for pagination
page_size (Optional): Number of items per page
sort_by (Optional): Field to sort by (e.g., ‘username’, ‘email’, ‘full_name’)
order (Optional): Sort order (‘asc’ or ‘desc’)
Request Format (PUT)
users: List of user identifiers (username or email)
role: The role to add users to
scope: The scope to add users to
Request Format (DELETE)
Query parameters:
users: Comma-separated list of user identifiers (username or email)
role: The role to remove users from
scope: The scope to remove users from
Response Format (GET)
Returns HTTP 200 OK with:
{ "count": 2, "next": null, "previous": null, "results": [ { "username": "john_doe", "email": "john_doe@example.com", "full_name": "John Doe" "roles": ["library_admin", "library_user"] }, { "username": "jane_doe", "email": "jane_doe@example.com", "full_name": "Jane Doe" "roles": ["library_user"] } ] }
Response Format (PUT)
Returns HTTP 207 Multi-Status with:
{ "completed": [{"user_identifier": "john_doe", "status": "role_added"}], "errors": [{"user_identifier": "jane_doe", "error": "user_already_has_role"}] }
Response Format (DELETE)
Returns HTTP 207 Multi-Status with:
{ "completed": [{"user_identifier": "john_doe", "status": "role_removed"}], "errors": [{"user_identifier": "jane_doe", "error": "user_does_not_have_role"}] }
Authentication and Permissions
Requires authenticated user.
GET: Requires
view_library_teamorview_course_teampermission according to the scope.PUT and DELETE: Requires
manage_library_teamormanage_course_teampermission according to the scope.
Example Request
GET /api/authz/v1/roles/users/?scope=lib:DemoX:CSPROB&search=john&roles=library_admin
PUT /api/authz/v1/roles/users/
{ "role": "library_admin", "scope": "lib:DemoX:CSPROB", "users": ["user1@example.com", "username2"] }
DELETE /api/authz/v1/roles/users/?role=library_admin&scope=lib:DemoX:CSPROB&users=user1@example.com,username2
- authentication_classes = [<class 'edx_rest_framework_extensions.auth.jwt.authentication.JwtAuthentication'>, <class 'edx_rest_framework_extensions.auth.session.authentication.SessionAuthenticationAllowInactiveUser'>]
- delete(request: HttpRequest) Response
Remove multiple users from a specific role within a scope.
- get(request: HttpRequest) Response
Retrieve all users with role assignments within a specific scope.
- pagination_class
alias of
AuthZAPIViewPagination
- permission_classes = [<class 'rest_framework.permissions.IsAuthenticated'>, <class 'openedx_authz.rest_api.v1.permissions.DynamicScopePermission'>]
- put(request: HttpRequest) Response
Assign multiple users to a specific role within one or more scopes.
- class openedx_authz.rest_api.v1.views.UserValidationAPIView(**kwargs)
Bases:
APIViewAPI view for validating that provided user identifiers correspond to existing users.
This view allows clients to verify that a list of user identifiers (usernames or emails) correspond to valid users in the system. It is designed to support bulk validation of multiple user identifiers in a single request, providing a convenient way to check the validity of users before performing operations such as role assignments.
Endpoints - POST: Validate that the provided list of usernames or emails correspond to existing users
Request Format (POST) - users: List of user identifiers (username or email)
Response Format (POST)
Returns HTTP 200 OK with:
{ "valid_users": ["john_doe", "jane@example.com"], "invalid_users": ["nonexistent_user"], "summary": { "total": 3, "valid_count": 2, "invalid_count": 1 } }
Authentication and Permissions
Requires authenticated user.
Requires
manage_library_teamormanage_course_teampermission in any scope.
Example Request
POST /api/authz/v1/users/validate/
{ "users": ["john_doe", "jane@example.com", "nonexistent_user"] }
- authentication_classes = [<class 'edx_rest_framework_extensions.auth.jwt.authentication.JwtAuthentication'>, <class 'edx_rest_framework_extensions.auth.session.authentication.SessionAuthenticationAllowInactiveUser'>]
- permission_classes = [<class 'rest_framework.permissions.IsAuthenticated'>, <class 'openedx_authz.rest_api.v1.permissions.AnyScopePermission'>]
- post(request: HttpRequest) Response
Validates the provided usernames or emails correspond to existing users.