---
id: AUTH-WEB
title: Websites Authorization Model
product_area: websites
revision: 1
status: draft
design_intent: proposed
implementation_evidence: partially-observed
source_sha:
  rhythm-v2-docs: 5dc44059e0010a877a57ae22ca80e74183f8d616
  services-websites: 5fc6823c69d5e6f208c21dba8c0eb3132f8bdc4c
  services-platform: ad3f6a6582843008ed0f5a17b131878d15829af1
  rhythm-web: 38aef7d26f1ab85b5c2a5be27e4b29df3698f193
  react-console: baf6dae382d6f41dce976c7f848667ccc37e076f
provenance: inferred
source: &ref_2
  - 'services-websites:aws/websites.service.ts'
  - 'services-websites:modules/changes/aws/api/changes.permissions.ts'
  - 'services-websites:modules/changes/aws/api/website-changes.routes.ts'
  - 'services-websites:modules/changes/aws/api/web-templates.routes.ts'
  - 'services-websites:modules/changes/aws/api/changes-mcp.routes.ts'
  - 'services-websites:modules/content/aws/api/content.permissions.ts'
  - 'services-websites:modules/content/aws/api/content.routes.ts'
  - 'services-platform:aws/platform.service.ts'
  - 'services-platform:modules/sites/aws/api/sites.routes.ts'
  - 'services-platform:modules/sites/aws/api/hq-sites.routes.ts'
  - 'services-platform:modules/sites/aws/api/websites.routes.ts'
  - 'services-platform:modules/sites/aws/api/web-releases.routes.ts'
  - 'services-platform:modules/security/services/catalog/reconcile-catalog.ts:builtInRoles'
  - 'services-platform:modules/security/authorizer/authorize.ts'
  - >-
    rhythm-v2-docs:specs/platform/security/planning/capabilities/CAP-PFM-SEC-015-decide-every-request-against-the-caller-s-grants.md
  - >-
    rhythm-v2-docs:specs/platform/security/design/workflows/WF-PFM-SEC-009-authorize-a-request-at-the-gateway.md
  - >-
    rhythm-v2-docs:specs/platform/security/planning/capabilities/CAP-PFM-SEC-017-let-rhythm-staff-into-a-customer-s-workspace-only-by-consent.md
  - 'rhythm-web:packages/web-contacts/src/server/calls.ts'
  - 'rhythm-web:packages/web-contacts/src/server/organization.ts'
  - 'services-websites:modules/content/app/src/console-editors.ts'
  - 'services-websites:modules/changes/services/mcp/confirmation-tokens.ts'
scopes:
  - name: customer
    meaning: Customer-wide assignments cover the customer’s applicable workspaces.
    provenance: documented
    source: >-
      rhythm-v2-docs:specs/platform/security/planning/capabilities/CAP-PFM-SEC-010-give-and-take-away-roles-at-the-right-scope.md
  - name: workspace
    meaning: Customer administration uses grants covering the workspace named by the request.
    provenance: documented
    source: >-
      rhythm-v2-docs:specs/platform/security/planning/capabilities/CAP-PFM-SEC-010-give-and-take-away-roles-at-the-right-scope.md
  - name: site
    meaning: >-
      Editor sessions and content checks narrow existing workspace authority to one site; no separate site
      role is established here.
    provenance: observed
    source: 'services-websites:modules/content/app/src/console-editors.ts'
  - name: record
    meaning: Portal adapters require a linked member record and defer final record authorization to CRM.
    provenance: observed
    source: 'rhythm-web:packages/web-contacts/src/server/calls.ts'
  - name: platform
    meaning: 'Staff-only system operations use platform-scoped authority, separate from customer assignments.'
    provenance: documented
    source: >-
      rhythm-v2-docs:specs/platform/security/planning/capabilities/CAP-PFM-SEC-010-give-and-take-away-roles-at-the-right-scope.md
roles:
  - id: ROLE-WEB-001
    name: Administrator
    who: A customer administrator assigned authority over the customer or selected workspaces.
    grants: &ref_0
      - websites.application.access
      - platform.sites.read
      - websites.website-changes.read
      - platform.sites.manage
      - websites.content.edit
      - websites.content.publish
      - websites.website-changes.change
      - websites.website-changes.source
      - websites.website-changes.publish
      - websites.website-changes.rollback
    provenance: observed
    source:
      - 'services-platform:modules/security/services/catalog/reconcile-catalog.ts:builtInRoles'
    note: >-
      Area-relevant keys only; assignments, deny rules, licence state and guards still determine effective
      access.
  - id: ROLE-WEB-002
    name: Power User
    who: A customer user with administrator-tier application powers but no security administration.
    grants: *ref_0
    provenance: observed
    source:
      - 'services-platform:modules/security/services/catalog/reconcile-catalog.ts:builtInRoles'
    note: >-
      Area-relevant keys only; assignments, deny rules, licence state and guards still determine effective
      access.
  - id: ROLE-WEB-003
    name: Standard User
    who: A customer user with everyday application authority.
    grants: &ref_1
      - websites.application.access
      - platform.sites.read
      - websites.website-changes.read
    provenance: observed
    source:
      - 'services-platform:modules/security/services/catalog/reconcile-catalog.ts:builtInRoles'
    note: >-
      Area-relevant keys only; assignments, deny rules, licence state and guards still determine effective
      access.
  - id: ROLE-WEB-004
    name: Read Only
    who: A customer user with application reading authority.
    grants: *ref_1
    provenance: observed
    source:
      - 'services-platform:modules/security/services/catalog/reconcile-catalog.ts:builtInRoles'
    note: >-
      Area-relevant keys only; assignments, deny rules, licence state and guards still determine effective
      access.
  - id: ROLE-WEB-005
    name: Portal Member
    who: A member using their own portal account.
    grants: []
    provenance: observed
    source:
      - 'services-platform:modules/security/services/catalog/reconcile-catalog.ts:builtInRoles'
    note: >-
      Area-relevant keys only; assignments, deny rules, licence state and guards still determine effective
      access.
  - id: ROLE-WEB-006
    name: Rhythm Administrator
    who: A Rhythm operator holding platform-scoped staff authority.
    grants:
      - hq.sites.read
      - hq.sites.manage
      - hq.web-releases.write
      - platform.tenants.onboard
      - websites.website-changes.review
      - websites.application.access
    provenance: observed
    source:
      - 'services-platform:modules/security/services/catalog/reconcile-catalog.ts:builtInRoles'
    note: >-
      Area-relevant keys only; assignments, deny rules, licence state and guards still determine effective
      access.
  - id: ROLE-WEB-007
    name: Support Representative
    who: A Rhythm support operator who can inspect HQ sites.
    grants:
      - hq.sites.read
    provenance: observed
    source:
      - 'services-platform:modules/security/services/catalog/reconcile-catalog.ts:builtInRoles'
    note: >-
      Area-relevant keys only; assignments, deny rules, licence state and guards still determine effective
      access.
  - id: ROLE-WEB-008
    name: Software Engineer
    who: A Rhythm engineer who can inspect HQ sites.
    grants:
      - hq.sites.read
    provenance: observed
    source:
      - 'services-platform:modules/security/services/catalog/reconcile-catalog.ts:builtInRoles'
    note: >-
      Area-relevant keys only; assignments, deny rules, licence state and guards still determine effective
      access.
  - id: ROLE-WEB-009
    name: 'Content editor, customer-defined profile'
    who: An author preparing drafts for a separate publisher.
    grants:
      - websites.application.access
      - platform.sites.read
      - websites.website-changes.read
      - websites.content.edit
    provenance: inferred
    source:
      - 'rhythm-v2-docs:specs/websites/ACTORS.md'
      - 'react-console:acceptance/websites/inventory/permissions.json'
    note: Illustrative customer-defined profile; not a shipped built-in role. Product intent is proposed.
  - id: ROLE-WEB-010
    name: 'Website change editor, customer-defined profile'
    who: An author preparing design revisions for a separate publisher.
    grants:
      - websites.application.access
      - platform.sites.read
      - websites.website-changes.read
      - websites.website-changes.change
    provenance: inferred
    source:
      - 'rhythm-v2-docs:specs/websites/ACTORS.md'
      - 'react-console:acceptance/websites/inventory/permissions.json'
    note: Illustrative customer-defined profile; not a shipped built-in role. Product intent is proposed.
permissions:
  - key: content reader key
    intent: Describe an access mechanism rather than an assignable permission.
    operations:
      - contentSystem.readPublishedContent
    surfaces:
      - console
      - api
    guarded_by: []
    entry_kind: access-descriptor
    provenance: documented
    source:
      - >-
        rhythm-v2-docs:specs/websites/websites/design/contracts/SVC-WEB-WEB-content.md#contentSystem.readPublishedContent
  - key: crm.organization-contacts.manage
    intent: 'Request additions, changes and removals on the member’s organization roster.'
    operations:
      - contacts.saveOrganizationContact
      - contacts.removeOrganizationContact
    surfaces:
      - portal
    guarded_by:
      - BR-CAP-WEB-WEB-022-04
      - BR-CAP-WEB-WEB-022-05
    entry_kind: permission
    provenance: observed
    source:
      - 'rhythm-web:packages/web-contacts/src/server/permissions.ts'
      - 'rhythm-web:packages/web-contacts/src/server/calls.ts'
    note: >-
      The adapter requests this key. CRM policy definitions and enforcement are outside the pinned source
      scope.
  - key: crm.organization.read
    intent: Request the member’s organization and its roster through CRM adapters.
    operations:
      - contacts.loadMyOrganization
      - contacts.loadOrganizationContacts
    surfaces:
      - portal
    guarded_by:
      - BR-CAP-WEB-WEB-022-01
    entry_kind: permission
    provenance: observed
    source:
      - 'rhythm-web:packages/web-contacts/src/server/permissions.ts'
      - 'rhythm-web:packages/web-contacts/src/server/calls.ts'
    note: >-
      The adapter requests this key. CRM policy definitions and enforcement are outside the pinned source
      scope.
  - key: crm.organization.update
    intent: Request changes to the member’s organization through CRM adapters.
    operations:
      - contacts.saveOrganization
    surfaces:
      - portal
    guarded_by:
      - BR-CAP-WEB-WEB-022-03
    entry_kind: permission
    provenance: observed
    source:
      - 'rhythm-web:packages/web-contacts/src/server/permissions.ts'
      - 'rhythm-web:packages/web-contacts/src/server/calls.ts'
    note: >-
      The adapter requests this key. CRM policy definitions and enforcement are outside the pinned source
      scope.
  - key: crm.self-contact-info.manage
    intent: Request changes to the member’s own contact points through CRM adapters.
    operations:
      - contacts.saveAddress
      - contacts.removeAddress
      - contacts.savePhoneNumber
      - contacts.removePhoneNumber
      - contacts.saveEmailAddress
      - contacts.removeEmailAddress
    surfaces:
      - portal
    guarded_by:
      - BR-CAP-WEB-WEB-021-04
      - BR-CAP-WEB-WEB-021-05
    entry_kind: permission
    provenance: observed
    source:
      - 'rhythm-web:packages/web-contacts/src/server/permissions.ts'
      - 'rhythm-web:packages/web-contacts/src/server/calls.ts'
    note: >-
      The adapter requests this key. CRM policy definitions and enforcement are outside the pinned source
      scope.
  - key: crm.self-contact.read
    intent: Request the member’s own profile and contact information through CRM adapters.
    operations:
      - contacts.loadMyProfile
      - contacts.saveProfile
      - contacts.saveCommunicationPreferences
      - contacts.loadMyContactInformation
    surfaces:
      - portal
    guarded_by:
      - BR-CAP-WEB-WEB-020-08
    entry_kind: permission
    provenance: observed
    source:
      - 'rhythm-web:packages/web-contacts/src/server/permissions.ts'
      - 'rhythm-web:packages/web-contacts/src/server/calls.ts'
    note: >-
      The adapter requests this key. CRM policy definitions and enforcement are outside the pinned source
      scope.
  - key: deployment refresh key
    intent: Describe an access mechanism rather than an assignable permission.
    operations:
      - rw.revalidate
    surfaces:
      - portal
      - api
    guarded_by: []
    entry_kind: access-descriptor
    provenance: documented
    source:
      - 'rhythm-v2-docs:specs/websites/websites/design/contracts/SVC-WEB-WEB-web-runtime.md#rw.revalidate'
  - key: deployment site-header key
    intent: Describe an access mechanism rather than an assignable permission.
    operations:
      - rw.previewSite
    surfaces:
      - portal
      - api
    guarded_by: []
    entry_kind: access-descriptor
    provenance: documented
    source:
      - 'rhythm-v2-docs:specs/websites/websites/design/contracts/SVC-WEB-WEB-web-runtime.md#rw.previewSite'
  - key: hq.sites.manage
    intent: Maintain customer sites and addresses through staff routes.
    operations:
      - createSiteForStaff
      - attachSiteDomainForStaff
      - detachSiteDomainForStaff
      - setSiteStatusForStaff
    surfaces:
      - api
    guarded_by:
      - BR-CAP-WEB-WEB-005-05
      - BR-CAP-WEB-WEB-005-07
    entry_kind: permission
    provenance: observed
    source:
      - 'services-platform:aws/platform.service.ts'
      - 'services-platform:modules/sites/aws/api'
  - key: hq.sites.read
    intent: Inspect customer sites and addresses through staff routes.
    operations:
      - listSitesForStaff
      - getSiteForStaff
      - listSiteDomainsForStaff
    surfaces:
      - api
    guarded_by: []
    entry_kind: permission
    provenance: observed
    source:
      - 'services-platform:aws/platform.service.ts'
      - 'services-platform:modules/sites/aws/api'
  - key: hq.web-releases.write
    intent: 'Read and maintain deployment, release and rollout records through staff routes.'
    operations:
      - createWebDeployment
      - listWebDeployments
      - getWebDeployment
      - updateWebDeployment
      - setDeploymentReleases
      - setDeploymentPin
      - getCurrentWebRelease
      - recordWebRelease
      - listWebReleases
      - getWebRelease
      - updateReleaseProgress
      - recordWebRollout
      - listWebRollouts
      - getWebRollout
      - setRolloutState
    surfaces:
      - api
    guarded_by:
      - BR-CAP-WEB-WEB-017-03
      - BR-CAP-WEB-WEB-017-09
    entry_kind: permission
    provenance: observed
    source:
      - 'services-platform:aws/platform.service.ts'
      - 'services-platform:modules/sites/aws/api'
  - key: member session
    intent: Describe an access mechanism rather than an assignable permission.
    operations:
      - account.signOut
      - account.changePassword
      - account.contactMatch
      - contacts.searchContactDirectory
      - contacts.searchOrganizationDirectory
      - contacts.loadDirectoryEntry
    surfaces:
      - portal
      - api
    guarded_by: []
    entry_kind: access-descriptor
    provenance: documented
    source:
      - 'rhythm-v2-docs:specs/websites/websites/design/contracts/SVC-WEB-WEB-web-runtime.md#account.signOut'
      - >-
        rhythm-v2-docs:specs/websites/websites/design/contracts/SVC-WEB-WEB-web-runtime.md#account.changePassword
      - >-
        rhythm-v2-docs:specs/websites/websites/design/contracts/SVC-WEB-WEB-web-runtime.md#account.contactMatch
      - >-
        rhythm-v2-docs:specs/websites/websites/design/contracts/SVC-WEB-WEB-web-runtime.md#contacts.searchContactDirectory
      - >-
        rhythm-v2-docs:specs/websites/websites/design/contracts/SVC-WEB-WEB-web-runtime.md#contacts.searchOrganizationDirectory
      - >-
        rhythm-v2-docs:specs/websites/websites/design/contracts/SVC-WEB-WEB-web-runtime.md#contacts.loadDirectoryEntry
  - key: none
    intent: Describe an access mechanism rather than an assignable permission.
    operations:
      - getWebsiteStudioMcpResourceMetadata
      - resolveSiteHost
      - proxy.routeRequest
      - rw.health
      - account.signUp
      - account.signIn
      - account.verifyEmail
      - account.resendVerification
      - account.requestPasswordReset
      - account.resetPassword
    surfaces:
      - portal
      - api
    guarded_by: []
    entry_kind: access-descriptor
    provenance: documented
    source:
      - >-
        rhythm-v2-docs:specs/websites/websites/design/contracts/SVC-WEB-WEB-changes.md#getWebsiteStudioMcpResourceMetadata
      - 'rhythm-v2-docs:specs/websites/websites/design/contracts/SVC-WEB-WEB-sites.md#resolveSiteHost'
      - 'rhythm-v2-docs:specs/websites/websites/design/contracts/SVC-WEB-WEB-web-runtime.md#proxy.routeRequest'
      - 'rhythm-v2-docs:specs/websites/websites/design/contracts/SVC-WEB-WEB-web-runtime.md#rw.health'
      - 'rhythm-v2-docs:specs/websites/websites/design/contracts/SVC-WEB-WEB-web-runtime.md#account.signUp'
      - 'rhythm-v2-docs:specs/websites/websites/design/contracts/SVC-WEB-WEB-web-runtime.md#account.signIn'
      - 'rhythm-v2-docs:specs/websites/websites/design/contracts/SVC-WEB-WEB-web-runtime.md#account.verifyEmail'
      - >-
        rhythm-v2-docs:specs/websites/websites/design/contracts/SVC-WEB-WEB-web-runtime.md#account.resendVerification
      - >-
        rhythm-v2-docs:specs/websites/websites/design/contracts/SVC-WEB-WEB-web-runtime.md#account.requestPasswordReset
      - >-
        rhythm-v2-docs:specs/websites/websites/design/contracts/SVC-WEB-WEB-web-runtime.md#account.resetPassword
  - key: platform.sites.manage
    intent: Create sites and maintain their availability and web addresses.
    operations:
      - createSite
      - updateSite
      - createSiteFromTemplate
      - getSiteHostnameAvailability
      - setSiteStatus
      - attachSiteDomain
      - setCanonicalSiteDomain
      - detachSiteDomain
    surfaces:
      - console
      - api
    guarded_by:
      - BR-CAP-WEB-WEB-002-06
      - BR-CAP-WEB-WEB-003-03
      - BR-CAP-WEB-WEB-004-03
      - BR-CAP-WEB-WEB-004-06
    entry_kind: permission
    provenance: observed
    source:
      - 'services-platform:aws/platform.service.ts'
      - 'services-platform:modules/sites/aws/api'
  - key: platform.sites.read
    intent: Inspect sites and their web addresses within the authorized workspace.
    operations:
      - listSites
      - getSite
      - listSiteDomains
    surfaces:
      - console
      - api
    guarded_by: []
    entry_kind: permission
    provenance: observed
    source:
      - 'services-platform:aws/platform.service.ts'
      - 'services-platform:modules/sites/aws/api'
  - key: platform.tenants.onboard
    intent: Prepare Websites and portal identity infrastructure through a staff operation.
    operations:
      - enableWebsites
    surfaces:
      - api
    guarded_by:
      - BR-CAP-WEB-WEB-005-07
    entry_kind: permission
    provenance: observed
    source:
      - 'services-platform:aws/platform.service.ts'
      - 'services-platform:modules/sites/aws/api'
  - key: preview grant
    intent: Describe an access mechanism rather than an assignable permission.
    operations:
      - contentSystem.readDraftContent
    surfaces:
      - console
      - api
    guarded_by: []
    entry_kind: access-descriptor
    provenance: documented
    source:
      - >-
        rhythm-v2-docs:specs/websites/websites/design/contracts/SVC-WEB-WEB-content.md#contentSystem.readDraftContent
  - key: registered handler’s eligibility rules; member session where required
    intent: Describe an access mechanism rather than an assignable permission.
    operations:
      - rw.pageData
    surfaces:
      - portal
      - api
    guarded_by: []
    entry_kind: access-descriptor
    provenance: documented
    source:
      - 'rhythm-v2-docs:specs/websites/websites/design/contracts/SVC-WEB-WEB-web-runtime.md#rw.pageData'
  - key: signed callback
    intent: Describe an access mechanism rather than an assignable permission.
    operations:
      - receiveWebsiteStudioCallback
    surfaces:
      - console
      - api
    guarded_by: []
    entry_kind: access-descriptor
    provenance: documented
    source:
      - >-
        rhythm-v2-docs:specs/websites/websites/design/contracts/SVC-WEB-WEB-changes.md#receiveWebsiteStudioCallback
  - key: signed handoff
    intent: Describe an access mechanism rather than an assignable permission.
    operations:
      - contentSystem.openEditorHandoff
    surfaces:
      - console
      - api
    guarded_by: []
    entry_kind: access-descriptor
    provenance: documented
    source:
      - >-
        rhythm-v2-docs:specs/websites/websites/design/contracts/SVC-WEB-WEB-content.md#contentSystem.openEditorHandoff
  - key: signed link token
    intent: Describe an access mechanism rather than an assignable permission.
    operations:
      - openWebsiteChangePreview
    surfaces:
      - console
      - api
    guarded_by: []
    entry_kind: access-descriptor
    provenance: documented
    source:
      - >-
        rhythm-v2-docs:specs/websites/websites/design/contracts/SVC-WEB-WEB-changes.md#openWebsiteChangePreview
  - key: signed lookup key
    intent: Describe an access mechanism rather than an assignable permission.
    operations:
      - lookupWebDeploymentForCms
      - contentSystem.seedSite
      - contentSystem.upsertContentReader
    surfaces:
      - console
      - api
    guarded_by: []
    entry_kind: access-descriptor
    provenance: documented
    source:
      - 'rhythm-v2-docs:specs/websites/websites/design/contracts/SVC-WEB-WEB-sites.md#lookupWebDeploymentForCms'
      - 'rhythm-v2-docs:specs/websites/websites/design/contracts/SVC-WEB-WEB-content.md#contentSystem.seedSite'
      - >-
        rhythm-v2-docs:specs/websites/websites/design/contracts/SVC-WEB-WEB-content.md#contentSystem.upsertContentReader
  - key: signed operations key
    intent: Describe an access mechanism rather than an assignable permission.
    operations:
      - contentSystem.runSiteOperation
    surfaces:
      - console
      - api
    guarded_by: []
    entry_kind: access-descriptor
    provenance: documented
    source:
      - >-
        rhythm-v2-docs:specs/websites/websites/design/contracts/SVC-WEB-WEB-content.md#contentSystem.runSiteOperation
  - key: signed webhook
    intent: Describe an access mechanism rather than an assignable permission.
    operations:
      - receiveWebsiteStudioGithubWebhook
    surfaces:
      - console
      - api
    guarded_by: []
    entry_kind: access-descriptor
    provenance: documented
    source:
      - >-
        rhythm-v2-docs:specs/websites/websites/design/contracts/SVC-WEB-WEB-changes.md#receiveWebsiteStudioGithubWebhook
  - key: websites.application.access
    intent: Enter the Websites application when its licence and access checks allow it.
    operations: []
    surfaces:
      - console
      - api
    guarded_by: []
    entry_kind: permission
    provenance: observed
    source:
      - 'services-websites:aws/websites.service.ts:ApplicationAccessPermission'
  - key: websites.content.edit
    intent: 'Prepare site content, save drafts and obtain editorial previews.'
    operations:
      - createSitePage
      - openSitePagePreview
      - createSiteMenu
      - saveSiteMenu
      - deleteSiteMenu
      - openContentEditorSession
      - moveSitePage
    surfaces:
      - console
      - api
    guarded_by:
      - BR-CAP-WEB-WEB-006-13
      - BR-CAP-WEB-WEB-006-14
      - BR-CAP-WEB-WEB-007-02
      - BR-CAP-WEB-WEB-007-05
      - BR-CAP-WEB-WEB-009-07
      - BR-CAP-WEB-WEB-009-10
    entry_kind: permission
    provenance: observed
    source:
      - 'services-websites:modules/content/aws/api/content.permissions.ts:CONTENT_PERMISSIONS'
      - 'services-websites:modules/content/aws/api/content.routes.ts'
  - key: websites.content.edit (evaluates websites.content.publish)
    intent: Describe the combined grant and evaluated authority already recorded by the service contract.
    operations:
      - openContentEditorSession
      - moveSitePage
    surfaces:
      - console
      - api
    guarded_by:
      - BR-CAP-WEB-WEB-006-13
      - BR-CAP-WEB-WEB-006-14
      - BR-CAP-WEB-WEB-007-02
      - BR-CAP-WEB-WEB-007-05
      - BR-CAP-WEB-WEB-009-07
      - BR-CAP-WEB-WEB-009-10
      - BR-CAP-WEB-WEB-006-08
      - BR-CAP-WEB-WEB-010-02
    entry_kind: access-descriptor
    provenance: documented
    source:
      - >-
        rhythm-v2-docs:specs/websites/websites/design/contracts/SVC-WEB-WEB-content.md#openContentEditorSession
      - 'rhythm-v2-docs:specs/websites/websites/design/contracts/SVC-WEB-WEB-content.md#moveSitePage'
  - key: websites.content.publish
    intent: 'Make editorial content live, including settings and eligible page moves.'
    operations:
      - publishSiteMenu
      - saveSiteSettings
      - openContentEditorSession
      - moveSitePage
    surfaces:
      - console
      - api
    guarded_by:
      - BR-CAP-WEB-WEB-006-08
      - BR-CAP-WEB-WEB-006-13
      - BR-CAP-WEB-WEB-006-14
      - BR-CAP-WEB-WEB-010-02
    entry_kind: permission
    provenance: observed
    source:
      - 'services-websites:modules/content/aws/api/content.permissions.ts:CONTENT_PERMISSIONS'
      - 'services-websites:modules/content/aws/api/content.routes.ts'
  - key: websites.website-changes.change
    intent: 'Prepare design work, save revisions and obtain previews without publishing it.'
    operations:
      - createWebsiteChange
      - requestWebsiteChangePreview
      - getWebsiteChangePreviewLink
      - createWebTemplate
      - duplicateWebTemplate
      - convertWebTemplateToCode
      - archiveWebTemplate
      - restoreWebTemplate
      - openWebTemplateChange
      - uploadTemplateAssets
      - persistWebsiteChangeRevision
    surfaces:
      - console
      - api
    guarded_by:
      - BR-CAP-WEB-WEB-011-05
      - BR-CAP-WEB-WEB-011-06
      - BR-CAP-WEB-WEB-012-03
      - BR-CAP-WEB-WEB-012-04
      - BR-CAP-WEB-WEB-012-08
      - BR-CAP-WEB-WEB-013-01
    entry_kind: permission
    provenance: observed
    source:
      - 'services-websites:modules/changes/aws/api/changes.permissions.ts:WEBSITE_CHANGES_PERMISSIONS'
      - 'services-websites:modules/changes/aws/api/website-changes.routes.ts'
      - 'services-websites:modules/changes/aws/api/web-templates.routes.ts'
  - key: websites.website-changes.change (evaluates websites.website-changes.source)
    intent: Describe the combined grant and evaluated authority already recorded by the service contract.
    operations:
      - persistWebsiteChangeRevision
    surfaces:
      - console
      - api
    guarded_by:
      - BR-CAP-WEB-WEB-011-05
      - BR-CAP-WEB-WEB-011-06
      - BR-CAP-WEB-WEB-012-03
      - BR-CAP-WEB-WEB-012-04
      - BR-CAP-WEB-WEB-012-08
      - BR-CAP-WEB-WEB-013-01
      - BR-CAP-WEB-WEB-011-10
    entry_kind: access-descriptor
    provenance: documented
    source:
      - >-
        rhythm-v2-docs:specs/websites/websites/design/contracts/SVC-WEB-WEB-changes.md#persistWebsiteChangeRevision
  - key: websites.website-changes.publish
    intent: Confirm publication of a specific website revision and retry eligible publication work.
    operations:
      - publishWebsiteChange
      - retryWebsiteChange
      - serveWebsiteStudioMcp
    surfaces:
      - console
      - api
    guarded_by:
      - BR-CAP-WEB-WEB-014-01
      - BR-CAP-WEB-WEB-014-02
      - BR-CAP-WEB-WEB-014-03
      - BR-CAP-WEB-WEB-014-05
      - BR-CAP-WEB-WEB-015-10
      - BR-CAP-WEB-WEB-015-12
    entry_kind: permission
    provenance: observed
    source:
      - 'services-websites:modules/changes/aws/api/changes.permissions.ts:WEBSITE_CHANGES_PERMISSIONS'
      - 'services-websites:modules/changes/aws/api/website-changes.routes.ts'
      - 'services-websites:modules/changes/aws/api/web-templates.routes.ts'
  - key: websites.website-changes.read
    intent: 'Inspect website changes, templates, content listings and delivery information.'
    operations:
      - listWebsiteChanges
      - getWebsiteChange
      - listWebsiteChangeEvents
      - getWebsiteChangeDiff
      - getWebsiteChangeProgress
      - getWebsiteChangePublishPreview
      - listWebsiteSiteReleases
      - getWebsiteSiteRollbackPreview
      - listWebsiteSites
      - listWebTemplates
      - getWebTemplate
      - listTemplateChangeFiles
      - readTemplateChangeFile
      - getSitePageTree
      - listSitePages
      - listSitePageTemplates
      - listSiteMenus
      - getSiteMenu
      - getSiteSettings
      - retryWebsiteChange
      - serveWebsiteStudioMcp
    surfaces:
      - console
      - api
    guarded_by: []
    entry_kind: permission
    provenance: observed
    source:
      - 'services-websites:modules/changes/aws/api/changes.permissions.ts:WEBSITE_CHANGES_PERMISSIONS'
      - 'services-websites:modules/changes/aws/api/website-changes.routes.ts'
      - 'services-websites:modules/changes/aws/api/web-templates.routes.ts'
  - key: websites.website-changes.read (evaluates the other keys)
    intent: Describe the combined grant and evaluated authority already recorded by the service contract.
    operations:
      - serveWebsiteStudioMcp
    surfaces:
      - console
      - api
    guarded_by: []
    entry_kind: access-descriptor
    provenance: documented
    source:
      - 'rhythm-v2-docs:specs/websites/websites/design/contracts/SVC-WEB-WEB-changes.md#serveWebsiteStudioMcp'
  - key: >-
      websites.website-changes.read (evaluates websites.website-changes.publish,
      websites.website-changes.rollback)
    intent: Describe the combined grant and evaluated authority already recorded by the service contract.
    operations:
      - retryWebsiteChange
    surfaces:
      - console
      - api
    guarded_by:
      - BR-CAP-WEB-WEB-014-01
      - BR-CAP-WEB-WEB-014-02
      - BR-CAP-WEB-WEB-014-03
      - BR-CAP-WEB-WEB-014-05
      - BR-CAP-WEB-WEB-015-10
      - BR-CAP-WEB-WEB-015-12
      - BR-CAP-WEB-WEB-018-02
      - BR-CAP-WEB-WEB-018-04
      - BR-CAP-WEB-WEB-018-06
      - BR-CAP-WEB-WEB-018-12
    entry_kind: access-descriptor
    provenance: documented
    source:
      - 'rhythm-v2-docs:specs/websites/websites/design/contracts/SVC-WEB-WEB-changes.md#retryWebsiteChange'
  - key: websites.website-changes.review
    intent: Decide escalated reviews and inspect or retry delivery work as Rhythm staff.
    operations:
      - getWebsiteChangeProgressForStaff
      - retryWebsiteChangeForStaff
      - reviewWebsiteChange
    surfaces:
      - api
    guarded_by:
      - BR-CAP-WEB-WEB-014-08
      - BR-CAP-WEB-WEB-014-09
    entry_kind: permission
    provenance: observed
    source:
      - 'services-websites:modules/changes/aws/api/changes.permissions.ts:WEBSITE_CHANGES_PERMISSIONS'
      - 'services-websites:modules/changes/aws/api/website-changes.routes.ts'
      - 'services-websites:modules/changes/aws/api/web-templates.routes.ts'
  - key: websites.website-changes.rollback
    intent: Request recovery of the previous customer application release and retry recovery work.
    operations:
      - rollbackWebsiteSite
      - retryWebsiteChange
      - serveWebsiteStudioMcp
    surfaces:
      - console
      - api
    guarded_by:
      - BR-CAP-WEB-WEB-018-02
      - BR-CAP-WEB-WEB-018-04
      - BR-CAP-WEB-WEB-018-06
      - BR-CAP-WEB-WEB-018-12
    entry_kind: permission
    provenance: observed
    source:
      - 'services-websites:modules/changes/aws/api/changes.permissions.ts:WEBSITE_CHANGES_PERMISSIONS'
      - 'services-websites:modules/changes/aws/api/website-changes.routes.ts'
      - 'services-websites:modules/changes/aws/api/web-templates.routes.ts'
  - key: websites.website-changes.source
    intent: Authorize component-source edits within an otherwise authorized revision save.
    operations:
      - persistWebsiteChangeRevision
    surfaces:
      - console
      - api
    guarded_by:
      - BR-CAP-WEB-WEB-011-10
      - BR-CAP-WEB-WEB-012-04
    entry_kind: permission
    provenance: observed
    source:
      - 'services-websites:modules/changes/aws/api/changes.permissions.ts:WEBSITE_CHANGES_PERMISSIONS'
      - 'services-websites:modules/changes/aws/api/website-changes.routes.ts'
      - 'services-websites:modules/changes/aws/api/web-templates.routes.ts'
staff_access: >-
  Platform-scoped staff roles authorize staff-only system routes. Ordinary customer work requires a separate
  active staff-access grant administered by Platform; HQ powers do not substitute for customer grants.
staff_access_provenance: documented
staff_access_source: >-
  rhythm-v2-docs:specs/platform/security/planning/capabilities/CAP-PFM-SEC-017-let-rhythm-staff-into-a-customer-s-workspace-only-by-consent.md
evidence: *ref_2
---

# Websites Authorization Model

## Authorization Boundary

Published website browsing is public. Customer administration uses Platform authentication, workspace grants, application access and licence state. Staff-only site administration, onboarding, release-ledger operations and escalated review use system routes with staff authority. A customer administrator’s broad application role does not confer those staff powers.

Public integration routes have their own trust boundaries: callbacks and webhooks require valid signatures, while draft and design previews require their respective grants. A public route designation does not make protected drafts or pipeline mutation available to anonymous callers. Portal adapters use member sessions and leave final record authorization with CRM.

## Scopes

Customer assignments may cover all applicable workspaces or selected workspaces. Workspace authority is narrowed by site and record checks where the operation requires them. An embedded editor session reaches one site. That restriction is a session guard, not a separately demonstrated site-role grant. Platform scope supplies staff authority; staff enter ordinary customer work through the separate consent-based access mechanism administered by Platform.

## Roles

Administrator and Power User share the application powers relevant to Websites. Standard User and Read Only receive its reading tier. Portal Member alone supplies no demonstrated website-administration or CRM adapter grant in the pinned built-in role definition. The CRM keys requested by portal adapters require separate authority whose complete entitlement policy is outside this examination.

Rhythm Administrator holds staff administration, onboarding, release-ledger and Websites review authority while those declarations are active in the catalog. Support Representative and Software Engineer can inspect HQ sites without acquiring customer website access. Content editor and website change editor describe illustrative customer-defined profiles. They are not additional shipped built-ins. An assistant has no role of its own and uses the connecting person’s permissions.

## Permission Catalogue

The grantable keys below come from service declarations or observed portal adapter requests. Operation references in the structured catalogue include both route permissions and additional authority evaluated by handlers. Application access is a separate gate rather than a substitute for an operation’s permission.

| Permission | Intent |
|---|---|
| `crm.organization-contacts.manage` | Request additions, changes and removals on the member’s organization roster. |
| `crm.organization.read` | Request the member’s organization and its roster through CRM adapters. |
| `crm.organization.update` | Request changes to the member’s organization through CRM adapters. |
| `crm.self-contact-info.manage` | Request changes to the member’s own contact points through CRM adapters. |
| `crm.self-contact.read` | Request the member’s own profile and contact information through CRM adapters. |
| `hq.sites.manage` | Maintain customer sites and addresses through staff routes. |
| `hq.sites.read` | Inspect customer sites and addresses through staff routes. |
| `hq.web-releases.write` | Read and maintain deployment, release and rollout records through staff routes. |
| `platform.sites.manage` | Create sites and maintain their availability and web addresses. |
| `platform.sites.read` | Inspect sites and their web addresses within the authorized workspace. |
| `platform.tenants.onboard` | Prepare Websites and portal identity infrastructure through a staff operation. |
| `websites.application.access` | Enter the Websites application when its licence and access checks allow it. |
| `websites.content.edit` | Prepare site content, save drafts and obtain editorial previews. |
| `websites.content.publish` | Make editorial content live, including settings and eligible page moves. |
| `websites.website-changes.change` | Prepare design work, save revisions and obtain previews without publishing it. |
| `websites.website-changes.publish` | Confirm publication of a specific website revision and retry eligible publication work. |
| `websites.website-changes.read` | Inspect website changes, templates, content listings and delivery information. |
| `websites.website-changes.review` | Decide escalated reviews and inspect or retry delivery work as Rhythm staff. |
| `websites.website-changes.rollback` | Request recovery of the previous customer application release and retry recovery work. |
| `websites.website-changes.source` | Authorize component-source edits within an otherwise authorized revision save. |

The structured catalogue also preserves the existing contracts’ combined permission expressions and access descriptors so every recorded operation can be reconciled without changing its contract. Those entries describe signatures, sessions, preview grants or evaluated combinations; they are not keys that a role can grant. CRM entries establish what the adapter requests, not a verified CRM policy or entitlement.

## Role Entitlement Matrix

This matrix shows the area-relevant baseline of each role. It does not override narrower assignment scopes, deny rules, licensing or resource guards. The two editorial profiles are illustrative customer roles.

| Permission | Administrator | Power User | Standard User | Read Only | Portal Member | Rhythm Administrator | Support Representative | Software Engineer | Content Editor | Change Editor |
|---|---|---|---|---|---|---|---|---|---|---|
| `crm.organization-contacts.manage` | — | — | — | — | — | — | — | — | — | — |
| `crm.organization.read` | — | — | — | — | — | — | — | — | — | — |
| `crm.organization.update` | — | — | — | — | — | — | — | — | — | — |
| `crm.self-contact-info.manage` | — | — | — | — | — | — | — | — | — | — |
| `crm.self-contact.read` | — | — | — | — | — | — | — | — | — | — |
| `hq.sites.manage` | — | — | — | — | — | Allow | — | — | — | — |
| `hq.sites.read` | — | — | — | — | — | Allow | Allow | Allow | — | — |
| `hq.web-releases.write` | — | — | — | — | — | Allow | — | — | — | — |
| `platform.sites.manage` | Allow | Allow | — | — | — | — | — | — | — | — |
| `platform.sites.read` | Allow | Allow | Allow | Allow | — | — | — | — | Allow | Allow |
| `platform.tenants.onboard` | — | — | — | — | — | Allow | — | — | — | — |
| `websites.application.access` | Allow | Allow | Allow | Allow | — | Allow | — | — | Allow | Allow |
| `websites.content.edit` | Allow | Allow | — | — | — | — | — | — | Allow | — |
| `websites.content.publish` | Allow | Allow | — | — | — | — | — | — | — | — |
| `websites.website-changes.change` | Allow | Allow | — | — | — | — | — | — | — | Allow |
| `websites.website-changes.publish` | Allow | Allow | — | — | — | — | — | — | — | — |
| `websites.website-changes.read` | Allow | Allow | Allow | Allow | — | — | — | — | Allow | Allow |
| `websites.website-changes.review` | — | — | — | — | — | Allow | — | — | — | — |
| `websites.website-changes.rollback` | Allow | Allow | — | — | — | — | — | — | — | — |
| `websites.website-changes.source` | Allow | Allow | — | — | — | — | — | — | — | — |

A dash means the role definition or illustrative profile supplies no grant for that key. It does not establish a deny, and other valid assignments may add authority. Portal CRM entitlements are not established by this matrix. The permission and role rows carry the evidence for its entries.

## Protected Actions

Publication requires confirmation of the current revision and readiness checks. Work classified for staff review waits for approval of that revision. Recovery targets the recorded previous customer application release and is restricted by the recovery workflow’s state. Retry evaluates publication or recovery authority according to the failed work even though its route opens with reading authority.

Source changes require source-edit authority in addition to the revision-saving route’s change grant. Content publication is independent of content editing. Settings saving publishes immediately; page moves and editor sessions evaluate publication authority separately. Assistant publication and recovery require a second call carrying a confirmation bound to the person and subject. That protocol alone does not prove a person approved the action.

## Guards Distinguished From Permissions

A permission grants a kind of action. A guard decides whether that action is valid for the selected resource and its current state. Workspace ownership, the editor’s selected site, linked member identity, current revision, release ownership, template readiness, record version and lifecycle state are guards. Signed callbacks, content-reader credentials and preview grants authenticate integration or delegated access; they do not become assignable permission keys.

Platform may reuse gateway decisions for sixty seconds, with signed contexts lasting thirty seconds beyond that bound. The embedded editor instead carries its publication claim for a two-hour session without a fresh Platform grant check. The latter is a recorded control gap, not a promise of immediate revocation.

## What People See When Refused

A missing operation grant produces a permission refusal. The editor explains that publishing requires publication authority and still permits a draft save. Foreign resources are generally presented as missing so the response does not disclose another workspace’s records; the module records paths whose narrower site guard is incomplete. Stale revisions and record versions require reloading or reconfirming current work.

A design preview link that is unknown answers Not Found; a revoked link answers Gone. Account sign-in uses the same error for an unknown address and an incorrect password. Member adapters translate missing authority into permission feedback and stale records into reload guidance. Assistant confirmation failures explain the invalid binding or expiry without returning the token’s contents, and unauthenticated assistant requests provide sign-in metadata.
