- Choose which permissions to grant
+ {validation?.scopeSelectable ? 'Choose which permissions to grant' : 'Permissions requested'}
-
- {Object.entries(scopesByGroup).map(([group, groupScopes]) => {
- const allGroupSelected = groupScopes.every(s => selectedScopes.includes(s))
- const someGroupSelected = groupScopes.some(s => selectedScopes.includes(s))
- return (
-
- {/* Group header with select-all toggle */}
-
- {/* Individual scopes */}
-
+
+ {validation?.scopeSelectable ? (
+ /* DCR client — user selects which scopes to grant */
+
+ {Object.entries(scopesByGroup).map(([group, groupScopes]) => {
+ const allGroupSelected = groupScopes.every(s => selectedScopes.includes(s))
+ const someGroupSelected = groupScopes.some(s => selectedScopes.includes(s))
+ return (
+
+
+
+ {groupScopes.map(s => {
+ const info = SCOPE_GROUPS[s]
+ return (
+
+ )
+ })}
+
+
+ )
+ })}
+
+ ) : (
+ /* Settings-created client — scopes are fixed, show read-only */
+
+ {Object.entries(scopesByGroup).map(([group, groupScopes]) => (
+
+
{group}
+
{groupScopes.map(s => {
const info = SCOPE_GROUPS[s]
- const checked = selectedScopes.includes(s)
return (
-
+
)
})}
- )
- })}
-
+ ))}
+
+ )}
)}
diff --git a/server/src/services/oauthService.ts b/server/src/services/oauthService.ts
index 3ffd1c45..6c4a045d 100644
--- a/server/src/services/oauthService.ts
+++ b/server/src/services/oauthService.ts
@@ -532,6 +532,8 @@ export interface ValidateAuthorizeResult {
consentRequired?: boolean;
/** true when the request is valid but user is not authenticated */
loginRequired?: boolean;
+ /** true when the client was registered via machine DCR — user may adjust scopes on the consent screen */
+ scopeSelectable?: boolean;
}
export function validateAuthorizeRequest(
@@ -596,6 +598,7 @@ export function validateAuthorizeRequest(
client: { name: client.name, allowed_scopes: allowedScopes },
scopes: grantedScopes,
consentRequired,
+ scopeSelectable: client.created_via === 'dcr',
};
}