-
Notifications
You must be signed in to change notification settings - Fork 0
OAuth Clients and Scopes
This page summarizes how OAuth client configuration should work for Claude, ChatGPT, and other MCP clients. It deliberately uses placeholders only.
Since #450, the server advertises exactly two canonical scopes:
read
write
write implies read — there is no longer a separate admin/build tier; every tool that used to require site.admin now just requires write.
Every scope string from the older four-tier model (content.read, content.write, site.admin, system.admin) and a few other historical aliases (mcp, reader, admin, system_admin, siteadmin) are still accepted, but purely as compatibility aliases that normalize to read or write — none of them are advertised as a recommended or distinct scope anymore. See Scope and Tool Matrix and docs/mcp-contract.md §6.12 for the exact alias table.
| Tier | Meaning |
|---|---|
| anonymous | safe public discovery and limited read-only tools, no scope required at the ACL layer |
read |
no scope required beyond holding any valid token (no client secret needed to obtain one) — full read surface, including drafts; every Anonymous tool plus all richer read tools |
write |
requires a registered OAuth client (secret + oauth-clients.yaml entry) — full read surface plus create/update/delete content, build/site-ops, and integrity/diagnostic tools |
Correction (2026-07-18, #498). "No auth at all" in the table above describes the tool-scope ACL, not whether
/mcpitself requires a bearer token. Production runs with OAuth enabled, and every/mcprequest without one gets a401challenge regardless of tool tier — see Pitfall Anonymous vs Authenticated Server.readis obtained via self-serve DCR + PKCE, not a bearerless request.
OAuth clients can be imported from:
/etc/mcp-hugo-server-go/oauth-clients.yaml
Example shape:
clients:
- id: claude-admin
secret: REPLACE_WITH_A_LONG_RANDOM_SECRET
scopes: ["read", "write", "admin"]
redirect_uris:
- "https://claude.ai/*"
enabled: true
- id: chatgpt-write
secret: REPLACE_WITH_A_LONG_RANDOM_SECRET
scopes: ["read", "write"]
redirect_uris:
- "https://chatgpt.com/connector/oauth/*"
enabled: trueRules:
- Keep this file outside the Git repository.
- Restrict permissions to the service user/root as appropriate.
- Never log or paste real client secrets.
- Import should upsert clients, not delete missing clients by default.
- Redirect URI patterns must be strict: HTTPS scheme, exact host, and exact path or explicit path-prefix pattern.
Allowed examples:
https://claude.ai/*
https://chatgpt.com/connector/oauth/*
Rejected examples:
http://claude.ai/callback
https://claude.ai.evil.example/callback
https://evil.example/callback
Dynamic Client Registration can help clients such as Claude.ai and ChatGPT connect without manual pre-registration. It must still be bounded by server-side policy:
- Unknown clients must not get write/admin scopes by default.
- Known redirect URI patterns may define the maximum allowed scope.
- Requested scopes can be downscoped, but must never be escalated.
- DCR-created clients must be persisted if clients are expected to survive restarts.
When Claude or ChatGPT authenticates but sees the wrong tools:
curl -sk https://mcp.arleo.eu/.well-known/oauth-authorization-server | jq .
curl -sk https://mcp.arleo.eu/.well-known/oauth-protected-resource | jq .
ssh hugo-vm 'journalctl -u mcp-hugo-server-go -n 120 --no-pager'Look for:
- client ID
- granted scope
- redirect URI match result
- resource/audience value
- whether
tools/listwas called with or withoutAuthorization
Do not log access tokens, refresh tokens, authorization codes, or client secrets.