fix(oid4vc): account for realm optional client scopes in credential scope resolution - #51237
fix(oid4vc): account for realm optional client scopes in credential scope resolution#51237aditya-cyberverse wants to merge 1 commit into
Conversation
fb9e9b4 to
aa1cb8c
Compare
There was a problem hiding this comment.
Pull request overview
Note
Copilot couldn't run its full agentic review because it didn't start before the timeout. Make sure your repository has a runner available, or add a copilot-code-review.yml file specifying one with the runs-on attribute. See the docs for more details.
Updates OID4VCI credential scope resolution to also consider Realm Optional Client Scopes when evaluating requested scopes during authorization and client policy checks.
Changes:
- Expanded scope resolution to union client default scopes, client optional scopes, and realm optional client scopes.
- Updated authorization and client policy call sites to pass
KeycloakSessioninto scope resolution.
Reviewed changes
Copilot reviewed 3 out of 3 changed files in this pull request and generated 3 comments.
| File | Description |
|---|---|
| services/src/main/java/org/keycloak/protocol/oid4vc/utils/CredentialScopeUtils.java | Expands scope lookup to include realm optional client scopes and changes API to require a session. |
| services/src/main/java/org/keycloak/protocol/oid4vc/issuance/OID4VCAuthorizationCheckProvider.java | Updates authorization checker to use the new scope-resolution signature. |
| services/src/main/java/org/keycloak/protocol/oid4vc/clientpolicy/CredentialClientPolicyExecutor.java | Updates client policy executor to use the new scope-resolution signature. |
| * Get the list of credential scopes associated by the given and requested by the given authorization request | ||
| */ | ||
| public static List<CredentialScopeModel> getCredentialScopesForAuthorization(ClientModel client, AuthorizationEndpointRequest request) { | ||
| public static List<CredentialScopeModel> getCredentialScopesForAuthorization(KeycloakSession session, ClientModel client, AuthorizationEndpointRequest request) { |
| Map<String, ClientScopeModel> clientScopes = client.getClientScopes(false); | ||
| // Get the list of requested credential scopes that are associated with this client. | ||
| // Include client default scopes, client optional scopes and realm optional client scopes. | ||
| RealmModel realm = session.getContext().getRealm(); |
| Map<String, ClientScopeModel> clientScopes = Stream.concat( | ||
| Stream.concat(client.getClientScopes(true).values().stream(), client.getClientScopes(false).values().stream()), | ||
| realm.getDefaultClientScopesStream(false)) | ||
| .collect(Collectors.toMap(ClientScopeModel::getName, Function.identity(), (existing, replacement) -> existing)); |
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 3 out of 3 changed files in this pull request and generated no new comments.
Comments suppressed due to low confidence (3)
services/src/main/java/org/keycloak/protocol/oid4vc/utils/CredentialScopeUtils.java:90
- The comment says this includes “realm optional client scopes”, but the call
realm.getDefaultClientScopesStream(false)is easy to misread as “default scopes” (and the boolean flag is non-obvious). If the RealmModel API provides a dedicated optional-scope stream method, prefer that for clarity. Otherwise, consider adding a short clarifying comment about what the boolean flag represents to prevent future regressions/misuse.
// Include client default scopes, client optional scopes and realm optional client scopes.
RealmModel realm = session.getContext().getRealm();
Map<String, ClientScopeModel> clientScopes = Stream.concat(
Stream.concat(client.getClientScopes(true).values().stream(), client.getClientScopes(false).values().stream()),
realm.getDefaultClientScopesStream(false))
services/src/main/java/org/keycloak/protocol/oid4vc/utils/CredentialScopeUtils.java:91
- This silently drops duplicate client scope names by keeping the first occurrence. If duplicates can happen (e.g., misconfiguration across client vs realm scope sets), this can hide configuration issues and make debugging difficult. Consider either (a) explicitly documenting the precedence being enforced, or (b) failing fast/logging when a duplicate name is encountered so the configuration problem is visible.
.collect(Collectors.toMap(ClientScopeModel::getName, Function.identity(), (existing, replacement) -> existing));
services/src/main/java/org/keycloak/protocol/oid4vc/utils/CredentialScopeUtils.java:78
- This utility now depends on
KeycloakSessionsolely to access the realm context. To reduce coupling and improve testability/reusability, consider passingRealmModel realm(or a precomputed stream/map of realm optional scopes) instead of the full session object, unless other session-derived data is expected to be needed here later.
public static List<CredentialScopeModel> getCredentialScopesForAuthorization(KeycloakSession session, ClientModel client, AuthorizationEndpointRequest request) {
…cope resolution Signed-off-by: aditya-cyberverse <aditya1107zagade@gmail.com>
aa1cb8c to
9b41d6e
Compare
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 3 out of 3 changed files in this pull request and generated 1 comment.
Comments suppressed due to low confidence (2)
services/src/main/java/org/keycloak/protocol/oid4vc/utils/CredentialScopeUtils.java:103
- The code/comment relies on the boolean semantics of
realm.getDefaultClientScopesStream(false)to represent “realm optional client scopes”, which is non-obvious and easy to misuse. Prefer calling an explicit API if available (e.g.,realm.getOptionalClientScopesStream()), or wrap the call in a clearly named helper method (e.g.,getRealmOptionalClientScopes(realm)) to make intent unambiguous and reduce future regressions.
realm.getDefaultClientScopesStream(false)
)
.flatMap(Function.identity())
.collect(Collectors.toMap(
ClientScopeModel::getName,
Function.identity(),
(existing, replacement) -> existing // Preserve client-level override priority
));
services/src/main/java/org/keycloak/protocol/oid4vc/utils/CredentialScopeUtils.java:75
- The Javadoc opening delimiter indentation/formatting changed (the
/**is now flush-left while surrounding code is indented). Consider reformatting to match the file’s existing style to keep diffs minimal and readability consistent.
/**
| // Get the list of requested credential scopes that are associated with this client | ||
| // | ||
| List<CredentialScopeModel> credScopes = CredentialScopeUtils.getCredentialScopesForAuthorization(client, request); | ||
| List<CredentialScopeModel> credScopes = CredentialScopeUtils.getCredentialScopesForAuthorization(session, client, request); |
Closes #51187
Summary
Updates OID4VCI scope evaluation in
CredentialScopeUtils,OID4VCAuthorizationCheckProvider, andCredentialClientPolicyExecutorto properly recognize and account for requested scopes configured as Realm Optional Client Scopes.