docs(auth): clarify unconditional offline_access advertising + test

Address round-1 claude-review nits on PR #894:
- Document why offline_access is advertised unconditionally (independent of
  settings.enable_offline_access): per RFC 8414, scopes_supported lists what
  the AS *can* support, with actual issuance still gated upstream by Nextcloud.
- Add a regression test proving the offline_access invariant holds on an empty
  FastMCP instance with no registered tools.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
Chris Coutinho
2026-06-11 15:35:28 +02:00
co-authored by Claude Opus 4.8
parent c30a795a1f
commit 570a651ac4
2 changed files with 16 additions and 0 deletions
@@ -541,6 +541,11 @@ def discover_all_scopes(mcp) -> list[str]:
# issues a refresh token when the MCP server's OIDC client is permitted the
# scope. Optional for clients (unlike the base OIDC scopes) and never tied
# to a tool, so it is added here rather than discovered from @require_scopes.
#
# Advertised unconditionally — independent of settings.enable_offline_access
# (which gates the server's own Flow 2 background access). Per RFC 8414,
# scopes_supported lists what the AS *can* support, not what it will always
# grant; the actual refresh token is still gated upstream by Nextcloud.
all_scopes.add("offline_access")
# Get all registered tools
+11
View File
@@ -87,3 +87,14 @@ def test_discover_all_scopes_always_includes_offline_access():
assert "offline_access" in scopes
# Base OIDC scopes and tool-derived scopes still come through.
assert {"openid", "profile", "email", "notes.read"}.issubset(scopes)
@pytest.mark.unit
def test_discover_all_scopes_offline_access_without_any_tools():
"""The offline_access invariant must not depend on any tool being registered."""
mcp = FastMCP(name="empty")
scopes = discover_all_scopes(mcp)
assert "offline_access" in scopes
assert {"openid", "profile", "email"}.issubset(scopes)