-
Notifications
You must be signed in to change notification settings - Fork 496
Open
Description
Context
We need a scope layer for OAuth tokens without duplicating the permission system.
We map scopes to existing RBAC permissions.
A new OAuthScopePermission class checks whether the token's scopes cover the view's required RBAC permission. Unmapped permissions are denied by default
Post grooming
- One global scope that ultimately ties to the user permissions
- No mapping here and park it for later
Enforcement rule
Effective permissions is the intersection between the user permissions and scopes granted
What to do
- Define the
SCOPE_PERMISSION_MAP:SCOPE_PERMISSION_MAP = { "flag:read": {VIEW_PROJECT, VIEW_FEATURE_STATE, VIEW_ENVIRONMENT}, "flag:write": {CREATE_FEATURE, UPDATE_FEATURE_STATE, DELETE_FEATURE}, # ... }
- Build
OAuthScopePermissionclass:- If request is not an OAuth token → return
True(no-op for session users) - If the view has no declared RBAC permission → deny (default deny)
- Look up which scopes cover the required RBAC permission → check the token has one
- If request is not an OAuth token → return
- Add
OAuthScopePermissionto the permission classes:permission_classes = [IsAuthenticated, OAuthScopePermission, ProjectPermission]
- Define scope list in DOT settings (
OAUTH2_PROVIDER["SCOPES"])
Scope-to-permission mapping
| Scope | RBAC Permissions | MCP Endpoints |
|---|---|---|
organisation:read |
(org membership) | GET /organisations/, /organisations/{id}/groups/, /organisations/{id}/invites/ |
organisation:write |
CREATE_PROJECT, MANAGE_USER_GROUPS |
POST /organisations/{id}/invites/ |
project:read |
VIEW_PROJECT, MANAGE_TAGS |
GET /organisations/{id}/projects/, /projects/{id}/, /projects/{id}/environments/ |
project:write |
CREATE_ENVIRONMENT |
PUT /projects/{id}/ |
environment:read |
VIEW_ENVIRONMENT |
GET /environments/ |
environment:write |
MANAGE_SEGMENT_OVERRIDES |
|
flag:read |
VIEW_PROJECT, VIEW_ENVIRONMENT |
GET /features/, /features/{id}/, /evaluation-data/, /code-references/, /feature-external-resources/, /mv-options/, /versions/, /featurestates/, /change-requests/, /list-change-requests/ |
flag:write |
CREATE_FEATURE, EDIT_FEATURE, DELETE_FEATURE, UPDATE_FEATURE_STATE, CREATE_CHANGE_REQUEST, APPROVE_CHANGE_REQUEST, MANAGE_PROJECT_LEVEL_CHANGE_REQUESTS, APPROVE_PROJECT_LEVEL_CHANGE_REQUESTS, CREATE_PROJECT_LEVEL_CHANGE_REQUESTS |
POST/PUT/DELETE on features, MV options, versions, feature states, change requests |
segment:read |
VIEW_PROJECT |
GET /segments/, /segments/{id}/ |
segment:write |
MANAGE_SEGMENTS |
POST /segments/, PUT /segments/{id}/ |
identity:read |
VIEW_IDENTITIES |
|
identity:write |
MANAGE_IDENTITIES |
|
release_pipeline:read |
VIEW_PROJECT |
GET /release-pipelines/, /release-pipelines/{id}/ |
release_pipeline:write |
(project admin) | POST /release-pipelines/{id}/add-feature/ |
feature_health:read |
VIEW_PROJECT |
GET /feature-health/events/ |
audit_log:read |
VIEW_AUDIT_LOG |
|
webhook:read |
(env/project membership) | |
webhook:write |
(env/project admin) | |
role:read |
(org admin) | |
role:write |
(org admin) | |
integration:read |
(project/env membership) | |
integration:write |
(project/env admin) |
SCOPE_PERMISSION_MAP = {
# Organisation
"organisation:read": set(), # org membership check
"organisation:write": {CREATE_PROJECT, MANAGE_USER_GROUPS},
# Project
"project:read": {VIEW_PROJECT, MANAGE_TAGS},
"project:write": {CREATE_ENVIRONMENT},
# Environment
"environment:read": {VIEW_ENVIRONMENT},
"environment:write": {MANAGE_SEGMENT_OVERRIDES},
# Flags (includes change requests)
"flag:read": {VIEW_PROJECT, VIEW_ENVIRONMENT},
"flag:write": {
CREATE_FEATURE, EDIT_FEATURE, DELETE_FEATURE, UPDATE_FEATURE_STATE,
CREATE_CHANGE_REQUEST, APPROVE_CHANGE_REQUEST,
MANAGE_PROJECT_LEVEL_CHANGE_REQUESTS, APPROVE_PROJECT_LEVEL_CHANGE_REQUESTS,
CREATE_PROJECT_LEVEL_CHANGE_REQUESTS,
},
# Segments
"segment:read": {VIEW_PROJECT},
"segment:write": {MANAGE_SEGMENTS},
# Identities
"identity:read": {VIEW_IDENTITIES},
"identity:write": {MANAGE_IDENTITIES},
# Release pipelines
"release_pipeline:read": {VIEW_PROJECT},
"release_pipeline:write": set(), # project admin check
# Feature health
"feature_health:read": {VIEW_PROJECT},
# Audit log
"audit_log:read": {VIEW_AUDIT_LOG},
# Webhooks
"webhook:read": set(), # env/project membership check
"webhook:write": set(), # env/project admin check
# Roles
"role:read": set(), # org admin check
"role:write": set(), # org admin check
# Integrations
"integration:read": set(), # project/env membership check
"integration:write": set(), # project/env admin check
}Definition of done
- Scope enforcement active for OAuth tokens
- Session users unaffected
- Unmapped RBAC permissions are denied for OAuth tokens
- A token with the relevant scopes can access the resources (e.g
flag:readcan read features but not create them) - A token without the required scope gets
403 insufficient_scope
Reactions are currently unavailable
Metadata
Metadata
Assignees
Labels
No labels