Skip to content

[High][Security] Reduce OAuth dynamic-client default scopes and disclose offline access on consent #304

Description

@richardcmckinney

Summary

OAuth dynamic client registration is enabled for unauthenticated clients, and the default scopes include write scopes plus offline_access. The consent page hides offline_access, so users may grant persistent refresh-token access without seeing it clearly.

Evidence

  • apps/web/src/lib/server/auth/index.ts:405-414 enables OAuth provider dynamic client registration and unauthenticated client registration.
  • apps/web/src/lib/server/auth/index.ts:416-429 defines broad read/write scopes plus offline_access.
  • apps/web/src/lib/server/auth/index.ts:431-444 sets default dynamic-client scopes including offline_access, write:feedback, write:changelog, write:article, and write:chat.
  • apps/web/src/routes/oauth/consent.tsx:93 hides offline_access in the consent UI.

Impact

A dynamically registered client can receive broad write permissions and persistent access by default. Users do not get clear disclosure that offline/persistent access is being granted.

Recommended fix

Make dynamic-client defaults least-privilege. Default to identity-only scopes, or at most read-only scopes. Require clients to explicitly request write scopes and offline access. Display offline access as “persistent access” or equivalent on the consent screen. Consider an admin setting to disable unauthenticated dynamic client registration.

Acceptance criteria

  • Dynamically registered clients do not receive write scopes by default.
    offline_access is never hidden from consent when requested or granted.
  • Consent copy clearly explains persistent access and revocation.
  • Tests prove a dynamically registered client with no explicit requested scopes cannot call write tools.
  • Admins can disable or restrict unauthenticated dynamic client registration.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions