Skip to content

Latest commit

 

History

History
139 lines (106 loc) · 5.4 KB

File metadata and controls

139 lines (106 loc) · 5.4 KB

ADR-024: OAuth Scope Separator Migration (colon to dot)

Status: Accepted Date: 2026-04-07 Supersedes: Scope naming conventions in ADR-004, ADR-009, ADR-011

Context

The MCP server defines application-level OAuth scopes using the resource:action pattern (e.g., notes:read, calendar:write). While the colon separator is visually intuitive and used by some OAuth implementations, it causes interoperability problems with many identity providers.

IDP Compatibility Issues

Several widely-deployed identity providers reject or mishandle colons in OAuth scope names:

  • Keycloak: Accepts colons but requires special configuration for scope mappers; colons can conflict with realm-qualified scope names
  • Auth0: Permits colons but treats them as namespace delimiters in their Resource Server API, leading to unexpected scope resolution behavior
  • Azure AD / Entra ID: Uses colons internally for delegated permissions (e.g., User.Read) and may reject custom scopes containing colons
  • AWS Cognito: Restricts scope names to alphanumeric characters, hyphens, periods, and underscores — colons are not allowed
  • Okta: Custom scopes are restricted to [a-zA-Z0-9._-]; colons are explicitly rejected

RFC References

The OAuth 2.0 framework (RFC 6749, Section 3.3) defines scope values as:

scope-token = 1*( %x21 / %x23-5B / %x5D-7E )

This technically permits the colon character (%x3A), so colons are spec-compliant. However, the specification also notes:

The authorization server MAY fully or partially ignore the scope requested by the client, based on the authorization server policy or the resource owner's instructions.

In practice, many authorization servers impose stricter character restrictions than the RFC minimum. The dot separator (.) is universally accepted across all major OAuth/OIDC implementations and is the de facto convention used by:

  • Microsoft Identity Platform (User.Read, Mail.Send)
  • Google OAuth (https://www.googleapis.com/auth/calendar.readonly)
  • MCP specification examples in RFC 9728 (OAuth Protected Resource Metadata)

RFC 9728 (OAuth Protected Resource Metadata)

RFC 9728 defines the Protected Resource Metadata endpoint used by this server (/.well-known/oauth-protected-resource). While the RFC does not mandate a specific scope naming convention, its examples and the broader OAuth ecosystem favor dot-separated scopes for maximum interoperability.

Decision

Replace the colon (:) separator with a dot (.) in all application-level OAuth scope names:

Before After
notes:read notes.read
notes:write notes.write
calendar:read calendar.read
calendar:write calendar.write
todo:read todo.read
todo:write todo.write
contacts:read contacts.read
contacts:write contacts.write
files:read files.read
files:write files.write
tables:read tables.read
tables:write tables.write
deck:read deck.read
deck:write deck.write
cookbook:read cookbook.read
cookbook:write cookbook.write
sharing:read sharing.read
sharing:write sharing.write
news:read news.read
news:write news.write
collectives:read collectives.read
collectives:write collectives.write
semantic:read semantic.read

Standard OIDC scopes (openid, profile, email, offline_access) are unchanged — they are defined by OIDC Core and do not use separators.

Consequences

Positive

  • Universal IDP compatibility: Dot-separated scopes work with every major identity provider without special configuration
  • Industry alignment: Matches the naming convention used by Microsoft, Google, and other major OAuth implementations
  • No logic changes: The authorization system uses string comparison and startswith() prefix matching — changing the separator character requires no algorithmic changes

Negative

  • Breaking change: Existing OAuth clients, stored tokens, and IDP configurations must be updated to use the new scope names
  • Migration required: An Alembic database migration updates stored scope strings in app_passwords and login_flow_sessions tables

Migration

  • Database: Alembic migration 004 handles REPLACE(scopes, ':', '.') on stored scope JSON
  • Keycloak: The realm export (keycloak/realm-export.json) has been updated; existing Keycloak deployments must re-import or manually update scope definitions
  • Nextcloud OIDC app: The astrolabe OAuth client hook (26-configure-astrolabe-oauth.sh) has been updated with new scope names
  • Existing MCP clients: Must update their scope requests to use dot separators; old colon-separated scope requests will be rejected

Alternatives Considered

Hyphen separator (notes-read)

Rejected: While universally compatible, hyphens are commonly used within scope component names (e.g., hypothetical file-share.read), creating ambiguity about which hyphen is the separator.

Underscore separator (notes_read)

Rejected: Also universally compatible but less conventional in the OAuth ecosystem. Dot is the dominant separator in industry practice.

Keep colons with IDP-specific workarounds

Rejected: Requires per-IDP configuration, documentation, and ongoing maintenance. The root cause is a poor separator choice, not an IDP deficiency.