-
Notifications
You must be signed in to change notification settings - Fork 8k
[OID4VCI] Inconsistencies in well-known OID4VC metadata (Same metadata for all formats) #45485 #45807
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Conversation
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Pull request overview
This pull request addresses inconsistencies in the OID4VCI well-known metadata endpoint by introducing format-specific metadata filtering. The PR adds a new extension point to allow credential builders to customize which metadata fields are exposed for each credential format, ensuring compliance with format-specific requirements.
Changes:
- Added
contributeToMetadata()method to theCredentialBuilderinterface as an extension point for format-specific metadata customization - Implemented metadata filtering in
JwtCredentialBuilder(removesvctfield) andSdJwtCredentialBuilder(removescredential_definitionfield) to ensure only format-appropriate fields are present - Updated
OID4VCIssuerWellKnownProviderto invoke the new extension point for each credential configuration using the factory pattern
Reviewed changes
Copilot reviewed 5 out of 5 changed files in this pull request and generated 2 comments.
Show a summary per file
| File | Description |
|---|---|
CredentialBuilder.java |
Added new contributeToMetadata() interface method with default no-op implementation for backward compatibility |
JwtCredentialBuilder.java |
Implemented contributeToMetadata() to remove vct field for JWT-VC format |
SdJwtCredentialBuilder.java |
Implemented contributeToMetadata() to remove credential_definition field for SD-JWT-VC format |
OID4VCIssuerWellKnownProvider.java |
Added applyFormatSpecificMetadata() method to apply format-specific metadata filtering using the credential builder factory pattern |
CredentialMetadataWellKnownTest.java |
Added integration tests to verify correct metadata exposure for SD-JWT and JWT-VC credential types |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| try { | ||
| Map<String, Object> metadataMap = JsonSerialization.readValue( | ||
| JsonSerialization.writeValueAsString(config), | ||
| new com.fasterxml.jackson.core.type.TypeReference<Map<String, Object>>() {} | ||
| ); | ||
|
|
||
| credentialBuilder.contributeToMetadata(metadataMap); | ||
|
|
||
| if (!metadataMap.containsKey("vct")) { | ||
| config.setVct(null); | ||
| } | ||
| if (!metadataMap.containsKey("credential_definition")) { | ||
| config.setCredentialDefinition(null); | ||
| } | ||
| } catch (Exception e) { | ||
| LOGGER.warnf(e, "Failed to apply format-specific metadata for format: %s", format); | ||
| } |
Copilot
AI
Jan 27, 2026
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The serialize-deserialize approach used here is inefficient and fragile. The code serializes the entire SupportedCredentialConfiguration to JSON, deserializes it to a Map, allows the builder to modify the map, then checks the map to determine which fields to set to null on the original config object. This creates unnecessary overhead and complexity.
A more direct and maintainable approach would be to:
- Pass the SupportedCredentialConfiguration object directly to contributeToMetadata, or
- Have the builders return a set of field names to remove, or
- Have specific methods on the interface like
shouldIncludeVct()andshouldIncludeCredentialDefinition()
This would eliminate the JSON serialization overhead and make the intent clearer.
| * | ||
| * @param metadata mutable map representing the credential metadata entry | ||
| */ | ||
| default void contributeToMetadata(Map<String,Object> metadata) { |
Copilot
AI
Jan 27, 2026
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Missing space after comma in generic type parameter. Should be Map<String, Object> to match the codebase convention seen throughout the project (e.g., in JwtCredentialBuilder.java:110, SdJwtCredentialBuilder.java:139, and many other files).
| default void contributeToMetadata(Map<String,Object> metadata) { | |
| default void contributeToMetadata(Map<String, Object> metadata) { |
074e7c1 to
88da126
Compare
|
@namanONcode Thanks! Could you please list existing issue (in the commit message and in the GH issue) and take care that "spotless" is working? See this message in your other PR for the details: #45809 (comment) |
88da126 to
82aef61
Compare
|
@mposolda i have fixes both pr issue related to contribution guidelines please allow ci to run for both pr |
mposolda
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@namanONcode Thanks! Added few comments inline. Could you check them please?
| * | ||
| * @param metadata mutable map representing the credential metadata entry | ||
| */ | ||
| default void contributeToMetadata(Map<String,Object> metadata) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It seems much better if this method has signature with "typed" arguments. Maybe something like:
default void contributeToMetadata(SupportedCredentialConfiguration credentialConfig, CredentialScopeModel credentialScope);
instead of generic map.
This would allow that method implementations can "add" proper fields to the credentialConfig rather than "remove" previously added fields.
It seems to me this might work if the method is invoked somewhen from SupportedCredentialConfiguration.parse (that method should be updated also to remove credentialConfiguration.setVct and credentialConfiguration.setCredentialDefinition to make sure that this is added by the corresponding builders).
|
|
||
| credentialBuilder.contributeToMetadata(metadataMap); | ||
|
|
||
| if (!metadataMap.containsKey("vct")) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It will be good if this is not needed. In theory, the OID4VCIssuerWellKnownProvider should not have any knowledge of the fields like vct or credential_definition, which are specific to concrete credential types. This is related to my other comment (in CredentialBuilder class).
| import static org.junit.Assert.assertNotNull; | ||
| import static org.junit.Assert.assertTrue; | ||
|
|
||
| public class CredentialMetadataWellKnownTest extends OID4VCIssuerEndpointTest { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is it possible to use existing OID4VCIssuerWellKnownProviderTest and either update some existing tests in that class or introduce new test methods to that class?
That test would be better as it is usually better approach to do end-to-end testing (properly send HTTP request to the endpoint instead of using testingClient.server.run to test Java API directly).
Just a note that there is some existing PR #45784, which will introduce conflicts, so probably may be good to wait until that one is merged (would be probably later today).
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
PR #45784 already merged. Feel free to rebase to align with latest updates in Keycloak main.
Yeah I will look and implement these comments |
82aef61 to
ae24a23
Compare
|
@mposolda i have done suggested changes mentioned in comments also test are also refactored please allow run ci and i had implemented with latest fork of main branch as you mentioned to avoid merge conflicts |
ae24a23 to
26e2cb6
Compare
mposolda
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@namanONcode Thanks for the updates! Added few more minor comments inline.
Besides that, it will be good to look at the failing tests as those are caused by your changes probably: https://github.com/keycloak/keycloak/actions/runs/21447397428/job/61767431090?pr=45807 .
Maybe it is not needed to add new test methods as the vct and credentialDefinition fields are probably already tested for some existing credentials. So maybe it is sufficient to fix the existing tests instead and that is sufficient to test that metadata looks as expected?
| public void contributeToMetadata(SupportedCredentialConfiguration credentialConfig, CredentialScopeModel credentialScope) { | ||
| String vct = Optional.ofNullable(credentialScope.getVct()).orElse(credentialScope.getName()); | ||
| credentialConfig.setVct(vct); | ||
| credentialConfig.setCredentialDefinition(null); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Minor: I think this line can be omitted as it is not needed to explicitly call setCredentialDefinition here? As long as it is not set on any other place (which is not with your changes), it would be null automatically. No need for this impl to take care of credentialDefinition, which this builder doesn't understand at all in theory.
| public void contributeToMetadata(SupportedCredentialConfiguration credentialConfig, CredentialScopeModel credentialScope) { | ||
| CredentialDefinition credentialDefinition = CredentialDefinition.parse(credentialScope); | ||
| credentialConfig.setCredentialDefinition(credentialDefinition); | ||
| credentialConfig.setVct(null); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Minor: I think this line can be omitted as it is not needed to explicitly call setVct here? As long as it is not set on any other place (which is not with your changes), it would be null automatically. No need for this impl to take care of vct, which this builder doesn't understand at all in theory.
| * This is an end-to-end test using HTTP requests to the well-known endpoint. | ||
| */ | ||
| @Test | ||
| public void testSdJwtMetadataContainsVctAndNotCredentialDefinition() { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think you can omit adding those new test methods, but instead, you can possibly update existing tests as there are some failure (with your changes), which are probably caused exactly by the fact that vct and credentialDefinition are not present.
BTW. If you think some new test is good to add, it would be good to avoid using Apache HTTP client directly, but instead using OAuthClient stuff (like other test methods of this class are using).
26e2cb6 to
2ee4199
Compare
|
@mposolda all new suggestions are implemented to avoid ci test failure still fails please guide me to resolve this |
2ee4199 to
b2759d6
Compare
Introduce a CredentialBuilder hook that allows credential formats to contribute format-specific metadata to the OID4VC issuer well-known configuration. The issuer delegates metadata shaping to the corresponding CredentialBuilder implementation. Refactor metadata contribution to work directly with SupportedCredentialConfiguration and CredentialScopeModel, improving type-safety and avoiding unnecessary serialization. Add integration tests to verify that SD-JWT credentials expose `vct` without `credential_definition`, and JWT_VC credentials expose `credential_definition` without `vct`. Closes keycloak#45485 Signed-off-by: NAMAN JAIN <[email protected]>
b2759d6 to
fa5f17b
Compare
This pull request enhances the flexibility and correctness of the OID4VC issuer metadata by allowing credential builders to contribute format-specific metadata to the well-known endpoint. It introduces a new extension point in the
CredentialBuilderinterface, updates the issuer provider to use it, and adds targeted tests to ensure correct metadata exposure for different credential formats.Format-specific metadata contribution:
contributeToMetadatamethod to theCredentialBuilderinterface, enabling each credential format to customize the metadata it exposes in the well-known endpoint. Default implementation is a no-op for backward compatibility.contributeToMetadatainJwtCredentialBuilderandSdJwtCredentialBuilderto ensure only relevant fields (credential_definitionorvct) are present in the metadata for each format. [1] [2]Provider logic updates:
OID4VCIssuerWellKnownProviderto invokecontributeToMetadatafor each supported credential configuration, using the factory pattern to obtain the correct builder for each format. This ensures that only format-appropriate metadata fields are included. [1] [2]Testing:
CredentialMetadataWellKnownTestto verify that the well-known endpoint exposes the correct metadata for SD-JWT and JWT-VC credential types, ensuring that only the appropriate fields are present for each format.These changes improve extensibility, ensure compliance with OID4VCI metadata requirements, and prevent leaking irrelevant metadata fields for unsupported formats.
Closes #45485