Service accounts and OAuth scopes

Inventory of inter-app service accounts (capability roles / access actions) and OAuth scopes (routes they gate). For credential variables and CLI vs HTTP auth, see API credentials and CLI authentication. For how scopes are registered and checked, see OAuth scopes (developer notes).

Service accounts

Capability roles and accounts are created idempotently on app finalize by the owning package (finalize_app / api_finalize_app). You can also run:

invenio kcworks-users ensure-service-capabilities

Accounts are active and confirmed with no local password (API / token use only). Do not grant them administration / admin.

Account

Email

Capability role(s)

Access action(s)

Owning package

svc-commons-profiles

svc-commons-profiles@service.kcworks.local

users-sync, groups-sync

users-sync, groups-sync

invenio-remote-user-data-kcworks

svc-commons-sso

svc-commons-sso@service.kcworks.local

users-logout

users-logout

invenio-remote-user-data-kcworks

svc-group-collections

svc-group-collections@service.kcworks.local

group-collections-write

group-collections-write

invenio-group-collections-kcworks

What each account may do

Account

Permission-policy gates

svc-commons-profiles

RemoteUserDataPermissionPolicy: can_trigger_users_sync, can_trigger_groups_sync

svc-commons-sso

RemoteUserDataPermissionPolicy: can_trigger_logout_user

svc-group-collections

GroupCollectionsPermissionPolicy: create / update / delete group collections (search/read stay ordinary community visibility)

Inbound static webhook impersonation

Until callers present OAuth for these accounts, inbound webhook bearers impersonate them via STATIC_API_TOKEN_ROUTES:

Bearer env var

User id config

Impersonates

COMMONS_PROFILES_API_TOKEN

STATIC_API_TOKEN_USER_ID_PROFILES

svc-commons-profiles

COMMONS_SSO_LOGOUT_API_TOKEN

STATIC_API_TOKEN_USER_ID_SSO

svc-commons-sso

Set the user id env vars to the numeric ids of those service users after they exist. Group-collection mutations use a normal OAuth token for svc-group-collections (no static bearer).

OAuth scopes and routes

External clients hit these under the /api mount. Rule paths below match the API Flask app (request.url_rule.rule, no /api prefix) unless noted.

Enforcement:

  • Central map — kcworks.config.oauth_scope_routes + API before_request (_check_oauth_token_scopes). Unmapped rule/method is currently a no-op (not denied).

  • View decorators — @require_oauth_scopes on webhook and group-collections handlers (listed below even when absent from the central map).

Authorization still also requires the token owner’s permission policy (capability roles for the service accounts above).

Scopes with route map entries

From KCWORKS_OAUTH_SCOPE_ROUTE_MAP (methods → required scopes; token must include all listed ids):

Scope

Routes (API app rule → methods)

records:read

/records/ GET; /records/<pid_value> GET; /records/<pid_value>/versions GET; /records/<pid_value>/versions/latest GET; /records/<pid_value>/files GET; /records/<pid_value>/files/<path:key> GET; /records/<pid_value>/files/<path:key>/content GET

records:write

/records/ POST; /records/<pid_value> DELETE; /records/<pid_value>/draft GET PUT DELETE POST; /records/<pid_value>/draft/actions/publish POST; /records/<pid_value>/versions POST

files:write

/records/<pid_value>/draft/files GET POST; /records/<pid_value>/draft/files/<path:key> GET DELETE; /records/<pid_value>/draft/files/<path:key>/content POST PUT; /records/<pid_value>/draft/files/<path:key>/commit POST; /records/<pid_value>/draft/actions/files-import POST

communities:read

/communities GET; /communities/<pid_value> GET; /communities/<pid_value>/members GET; /communities/<pid_value>/invitations GET; /communities/<pid_value>/membership-requests GET

communities:write

/communities POST; /communities/<pid_value> PUT DELETE; /communities/<pid_value>/members POST PUT DELETE; /communities/<pid_value>/invitations POST; /communities/<pid_value>/membership-requests POST

requests:write

/requests GET; /requests/<request_pid_value> GET; /requests/<request_pid_value>/actions/<action> POST

users:read

/users GET; /users/<id> GET

groups:read

/groups GET

stats:read

/stats POST

Registered but not yet mapped to a route in that table (UI / future use): records:export, users:write, groups:write.

Scopes enforced on package views

Scope

Routes (external /api…)

Methods

Notes

webhooks:user-data

/api/webhooks/users/update, /api/webhooks/user_data_update (deprecated)

GET, POST

Internal scope; @require_oauth_scopes on RUD views. Static bearer → svc-commons-profiles.

webhooks:logout

/api/webhooks/users/logout

GET, POST

Internal scope; @require_oauth_scopes on RUD views. Static bearer → svc-commons-sso.

group-collections:read

/api/group_collections/, /api/group_collections/<slug>

GET

@require_oauth_scopes on GC resource.

group-collections:write

/api/group_collections/ POST; /api/group_collections/<slug> PUT PATCH DELETE

as listed

@require_oauth_scopes on GC resource. Prefer token owned by svc-group-collections.

Upstream scopes

Scope

Package

Notes

user:email

invenio-oauth2server

Shown in personal-token UI

tokens:generate

invenio-rdm-records

internal=True