diff --git a/src/Hyperledger.Aries/Features/OpenID4VC/VCI/Models/Authorization/AuthorizationServerMetadata.cs b/src/Hyperledger.Aries/Features/OpenID4VC/VCI/Models/Authorization/AuthorizationServerMetadata.cs index 3960a044..0cce3fce 100644 --- a/src/Hyperledger.Aries/Features/OpenID4VC/VCI/Models/Authorization/AuthorizationServerMetadata.cs +++ b/src/Hyperledger.Aries/Features/OpenID4VC/VCI/Models/Authorization/AuthorizationServerMetadata.cs @@ -25,8 +25,8 @@ public class AuthorizationServerMetadata /// Gets or sets the response types that the OAuth 2.0 Authorization Server supports. /// These types determine how the Authorization Server responds to client requests. /// - [JsonProperty("response_types_supported")] - public string[] ResponseTypesSupported { get; set; } + [JsonProperty("response_types_supported", NullValueHandling = NullValueHandling.Ignore)] + public string[]? ResponseTypesSupported { get; set; } /// /// Gets or sets the supported authentication methods the OAuth 2.0 Authorization Server supports diff --git a/src/Hyperledger.Aries/Features/OpenID4VC/VCI/Models/CredentialOffer/OidCredentialOffer.cs b/src/Hyperledger.Aries/Features/OpenID4VC/VCI/Models/CredentialOffer/OidCredentialOffer.cs index 48e64891..ec77b0d2 100644 --- a/src/Hyperledger.Aries/Features/OpenID4VC/VCI/Models/CredentialOffer/OidCredentialOffer.cs +++ b/src/Hyperledger.Aries/Features/OpenID4VC/VCI/Models/CredentialOffer/OidCredentialOffer.cs @@ -21,10 +21,10 @@ public class OidCredentialOffer /// /// Gets or sets the list of credentials that the Wallet may request. The List contains CredentialMetadataIds - /// that must map to the keys in the credentials_supported dictionary of the Issuer Metadata + /// that must map to the keys in the credential_configurations_supported dictionary of the Issuer Metadata /// - [JsonProperty("credentials")] - public List Credentials { get; set; } = null!; + [JsonProperty("credential_configuration_ids")] + public List CredentialConfigurationIds { get; set; } = null!; /// /// Gets or sets the URL of the Credential Issuer from where the Wallet is requested to obtain one or more Credentials diff --git a/src/Hyperledger.Aries/Features/OpenID4VC/VCI/Models/CredentialRequest/OidCredentialRequest.cs b/src/Hyperledger.Aries/Features/OpenID4VC/VCI/Models/CredentialRequest/OidCredentialRequest.cs index fd78b3e3..cbacfab2 100644 --- a/src/Hyperledger.Aries/Features/OpenID4VC/VCI/Models/CredentialRequest/OidCredentialRequest.cs +++ b/src/Hyperledger.Aries/Features/OpenID4VC/VCI/Models/CredentialRequest/OidCredentialRequest.cs @@ -1,4 +1,5 @@ -using Hyperledger.Aries.Features.OpenId4Vc.Vci.Models.Metadata.Credential; +using System.Collections.Generic; +using Hyperledger.Aries.Features.OpenId4Vc.Vci.Models.Metadata.Credential.Attributes; using Newtonsoft.Json; namespace Hyperledger.Aries.Features.OpenId4Vc.Vci.Models.CredentialRequest @@ -21,11 +22,17 @@ public class OidCredentialRequest /// [JsonProperty("format")] public string Format { get; set; } = null!; - + + /// + /// Gets or sets the dictionary representing the attributes of the credential in different languages. + /// + [JsonProperty("claims")] + public Dictionary? Claims { get; set; } + /// - /// Gets or sets the Credential Definition. + /// Gets or sets the verifiable credential type (vct). /// - [JsonProperty("credential_definition")] - public OidCredentialDefinition CredentialDefinition { get; set; } = null!; + [JsonProperty("vct")] + public string Vct { get; set; } = null!; } } diff --git a/src/Hyperledger.Aries/Features/OpenID4VC/VCI/Models/CredentialResponse/OidCredentialResponse.cs b/src/Hyperledger.Aries/Features/OpenID4VC/VCI/Models/CredentialResponse/OidCredentialResponse.cs index 3f4afe2d..7b37f547 100644 --- a/src/Hyperledger.Aries/Features/OpenID4VC/VCI/Models/CredentialResponse/OidCredentialResponse.cs +++ b/src/Hyperledger.Aries/Features/OpenID4VC/VCI/Models/CredentialResponse/OidCredentialResponse.cs @@ -17,12 +17,6 @@ public class OidCredentialResponse [JsonProperty("c_nonce_expires_in")] public int? CNonceExpiresIn { get; set; } - /// - /// REQUIRED. JSON string denoting the format of the issued Credential. - /// - [JsonProperty("format")] - public string Format { get; set; } = null!; - /// /// OPTIONAL. A JSON string containing a security token subsequently used to obtain a Credential. /// MUST be present when credential is not returned. diff --git a/src/Hyperledger.Aries/Features/OpenID4VC/VCI/Models/Metadata/Credential/OidCredentialMetadata.cs b/src/Hyperledger.Aries/Features/OpenID4VC/VCI/Models/Metadata/Credential/OidCredentialMetadata.cs index 7807c40a..9d831aea 100644 --- a/src/Hyperledger.Aries/Features/OpenID4VC/VCI/Models/Metadata/Credential/OidCredentialMetadata.cs +++ b/src/Hyperledger.Aries/Features/OpenID4VC/VCI/Models/Metadata/Credential/OidCredentialMetadata.cs @@ -1,6 +1,7 @@ #nullable enable using System.Collections.Generic; +using Hyperledger.Aries.Features.OpenId4Vc.Vci.Models.Metadata.Credential.Attributes; using Newtonsoft.Json; namespace Hyperledger.Aries.Features.OpenId4Vc.Vci.Models.Metadata.Credential @@ -11,10 +12,16 @@ namespace Hyperledger.Aries.Features.OpenId4Vc.Vci.Models.Metadata.Credential public class OidCredentialMetadata { /// - /// Gets or sets the credential definition which specifies a specific credential. + /// Gets or sets the verifiable credential type (vct). /// - [JsonProperty("credential_definition")] - public OidCredentialDefinition CredentialDefinition { get; set; } = null!; + [JsonProperty("vct")] + public string Vct { get; set; } = null!; + + /// + /// Gets or sets the dictionary representing the attributes of the credential in different languages. + /// + [JsonProperty("claims")] + public Dictionary? Claims { get; set; } /// /// Gets or sets a list of display properties of the supported credential for different languages. @@ -30,10 +37,11 @@ public class OidCredentialMetadata public List? CryptographicBindingMethodsSupported { get; set; } /// - /// Gets or sets a list of identifiers for the cryptographic suites that are supported. + /// Gets or sets a list of identifiers for the signing algorithms that are supported by the issuer and used + /// to sign credentials. /// - [JsonProperty("cryptographic_suites_supported", NullValueHandling = NullValueHandling.Ignore)] - public List? CryptographicSuitesSupported { get; set; } + [JsonProperty("credential_signing_alg_values_supported", NullValueHandling = NullValueHandling.Ignore)] + public List? CredentialSigningAlgValuesSupported { get; set; } /// /// A list of claim display names, arranged in the order in which they should be displayed by the Wallet. @@ -52,5 +60,23 @@ public class OidCredentialMetadata /// [JsonProperty("id", NullValueHandling = NullValueHandling.Ignore)] public string? Id { get; set; } + + /// + /// Gets or sets a dictionary which maps a credential type to its supported signing algorithms for key proofs. + /// + [JsonProperty("proof_types_supported", NullValueHandling = NullValueHandling.Ignore)] + public Dictionary? ProofTypesSupported { get; set; } + } + + /// + /// Represents credential type specific signing algorithm information. + /// + public class OidCredentialProofType + { + /// + /// Gets or sets the available signing algorithms for the associated credential type. + /// + [JsonProperty("proof_signing_alg_values_supported")] + public string[] ProofSigningAlgValuesSupported { get; set; } = null!; } } diff --git a/src/Hyperledger.Aries/Features/OpenID4VC/VCI/Models/Metadata/Issuer/OidIssuerMetadata.cs b/src/Hyperledger.Aries/Features/OpenID4VC/VCI/Models/Metadata/Issuer/OidIssuerMetadata.cs index 942b66b6..ce31d4a3 100644 --- a/src/Hyperledger.Aries/Features/OpenID4VC/VCI/Models/Metadata/Issuer/OidIssuerMetadata.cs +++ b/src/Hyperledger.Aries/Features/OpenID4VC/VCI/Models/Metadata/Issuer/OidIssuerMetadata.cs @@ -14,8 +14,8 @@ public class OidIssuerMetadata /// /// Gets or sets a dictionary which maps a CredentialMetadataId to its credential metadata. /// - [JsonProperty("credentials_supported")] - public Dictionary CredentialsSupported { get; set; } = null!; + [JsonProperty("credential_configurations_supported")] + public Dictionary CredentialConfigurationsSupported { get; set; } = null!; /// /// Gets or sets a list of display properties of a Credential Issuer for different languages. @@ -54,7 +54,7 @@ public class OidIssuerMetadata /// metadata. /// public List? GetCredentialDisplay(string credentialMetadataId) - => CredentialsSupported[credentialMetadataId].Display; + => CredentialConfigurationsSupported[credentialMetadataId].Display; /// /// Gets the claim attributes of a given Credential. @@ -65,7 +65,7 @@ public class OidIssuerMetadata /// null if the Credential is not found in the metadata. /// public Dictionary? GetCredentialClaims(string credentialMetadataId) => - CredentialsSupported[credentialMetadataId].CredentialDefinition.Claims; + CredentialConfigurationsSupported[credentialMetadataId].Claims; /// /// Gets the localized attribute names of a given Credential for a specific locale. @@ -80,12 +80,12 @@ public class OidIssuerMetadata { var displayNames = new List(); - var matchingCredential = CredentialsSupported[credentialMetadataId]; + var matchingCredential = CredentialConfigurationsSupported[credentialMetadataId]; if (matchingCredential == null) return null; - var localeDisplayNames = matchingCredential.CredentialDefinition.Claims + var localeDisplayNames = matchingCredential.Claims .SelectMany(subject => subject.Value.Display) .Where(display => display.Locale == locale) .Select(display => display.Name); diff --git a/src/Hyperledger.Aries/Features/OpenID4VC/VCI/Services/Oid4VciClientService/IOid4VciClientService.cs b/src/Hyperledger.Aries/Features/OpenID4VC/VCI/Services/Oid4VciClientService/IOid4VciClientService.cs index 2a277e7d..337884ef 100644 --- a/src/Hyperledger.Aries/Features/OpenID4VC/VCI/Services/Oid4VciClientService/IOid4VciClientService.cs +++ b/src/Hyperledger.Aries/Features/OpenID4VC/VCI/Services/Oid4VciClientService/IOid4VciClientService.cs @@ -17,8 +17,9 @@ public interface IOid4VciClientService /// Fetches the metadata related to the OID issuer from the specified endpoint. /// /// The endpoint URL to retrieve the issuer metadata. + /// The preferred language of the wallet in which it would like to retrieve the issuer metadata. The default is "en" /// A task that represents the asynchronous operation. The task result contains the OID issuer metadata. - Task FetchIssuerMetadataAsync(Uri endpoint); + Task FetchIssuerMetadataAsync(Uri endpoint, string preferredLanguage = "en"); /// /// Requests a verifiable credential using the provided parameters. diff --git a/src/Hyperledger.Aries/Features/OpenID4VC/VCI/Services/Oid4VciClientService/Oid4VciClientService.cs b/src/Hyperledger.Aries/Features/OpenID4VC/VCI/Services/Oid4VciClientService/Oid4VciClientService.cs index e66c4be3..d4576943 100644 --- a/src/Hyperledger.Aries/Features/OpenID4VC/VCI/Services/Oid4VciClientService/Oid4VciClientService.cs +++ b/src/Hyperledger.Aries/Features/OpenID4VC/VCI/Services/Oid4VciClientService/Oid4VciClientService.cs @@ -45,7 +45,7 @@ public Oid4VciClientService( private const string UseDPopNonceError = "use_dpop_nonce"; /// - public async Task FetchIssuerMetadataAsync(Uri endpoint) + public async Task FetchIssuerMetadataAsync(Uri endpoint, string preferredLanguage) { var baseEndpoint = endpoint .AbsolutePath @@ -55,9 +55,10 @@ public async Task FetchIssuerMetadataAsync(Uri endpoint) var metadataUrl = new Uri(baseEndpoint, ".well-known/openid-credential-issuer"); - var response = await _httpClientFactory - .CreateClient() - .GetAsync(metadataUrl); + var client = _httpClientFactory.CreateClient(); + client.DefaultRequestHeaders.Add("Accept-Language", preferredLanguage); + + var response = await client.GetAsync(metadataUrl); if (!response.IsSuccessStatusCode) { @@ -227,7 +228,7 @@ private async Task RequestTokenWithDPop( content: new OidCredentialRequest { Format = credentialMetadata.Format, - CredentialDefinition = credentialMetadata.CredentialDefinition, + Vct = credentialMetadata.Vct, Proof = new OidProofOfPossession { ProofType = "jwt", @@ -256,7 +257,7 @@ private async Task RequestTokenWithDPop( content: new OidCredentialRequest { Format = credentialMetadata.Format, - CredentialDefinition = credentialMetadata.CredentialDefinition, + Vct = credentialMetadata.Vct, Proof = new OidProofOfPossession { ProofType = "jwt", @@ -349,7 +350,7 @@ private async Task RequestTokenWithoutDPop( content: new OidCredentialRequest { Format = credentialMetadata.Format, - CredentialDefinition = credentialMetadata.CredentialDefinition, + Vct = credentialMetadata.Vct, Proof = new OidProofOfPossession { ProofType = "jwt", diff --git a/src/Hyperledger.Aries/Features/SdJwt/Models/Records/SdJwtRecord.cs b/src/Hyperledger.Aries/Features/SdJwt/Models/Records/SdJwtRecord.cs index 6cc515c6..6886a7a0 100644 --- a/src/Hyperledger.Aries/Features/SdJwt/Models/Records/SdJwtRecord.cs +++ b/src/Hyperledger.Aries/Features/SdJwt/Models/Records/SdJwtRecord.cs @@ -162,7 +162,7 @@ public void SetDisplayFromIssuerMetadata( { Display = issuerMetadata.GetCredentialDisplay(credentialMetadataId); DisplayedAttributes = issuerMetadata.GetCredentialClaims(credentialMetadataId); - AttributeOrder = issuerMetadata.CredentialsSupported[credentialMetadataId].Order; + AttributeOrder = issuerMetadata.CredentialConfigurationsSupported[credentialMetadataId].Order; IssuerId = issuerMetadata.CredentialIssuer; IssuerName = CreateIssuerNameDictionary(issuerMetadata); diff --git a/test/Hyperledger.Aries.Tests/Features/OpenId4Vc/Vci/Services/Oid4VciClientServiceTests.cs b/test/Hyperledger.Aries.Tests/Features/OpenId4Vc/Vci/Services/Oid4VciClientServiceTests.cs index bbf0d0f6..adb3977f 100644 --- a/test/Hyperledger.Aries.Tests/Features/OpenId4Vc/Vci/Services/Oid4VciClientServiceTests.cs +++ b/test/Hyperledger.Aries.Tests/Features/OpenId4Vc/Vci/Services/Oid4VciClientServiceTests.cs @@ -22,7 +22,7 @@ public class Oid4VciClientServiceTests { private const string AuthServerMetadataWithoutDpop = "{\"issuer\":\"https://issuer.io\",\"token_endpoint\":\"https://issuer.io/token\",\"token_endpoint_auth_methods_supported\":[\"urn:ietf:params:oauth:client-assertion-type:verifiable-presentation\"],\"response_types_supported\":[\"urn:ietf:params:oauth:grant-type:pre-authorized_code\"]}\n"; - + //"{\"credential_issuer\":\"https://issuer.io/\",\"credential_endpoint\":\"https://issuer.io/credential\",\"display\":[{\"name\":\"Aussteller\",\"locale\":\"de-DE\"},{\"name\":\"Issuer\",\"locale\":\"en-US\"}],\"credential_configurations_supported\":{\"IdentityCredential\":{\"format\":\"vc+sd-jwt\",\"scope\":\"IdentityCredential_SD-JWT-VC\",\"cryptographic_binding_methods_supported\":[\"did:example\"],\"credential_signing_alg_values_supported\":[\"ES256K\"],\"display\":[{\"name\":\"IdentityCredential\",\"locale\":\"en-US\",\"background_color\":\"#12107c\",\"text_color\":\"#FFFFFF\"}],\"credential_definition\":{\"type\":\"IdentityCredential\",\"claims\":{\"given_name\":{\"display\":[{\"name\":\"GivenName\",\"locale\":\"en-US\"},{\"name\":\"Vorname\",\"locale\":\"de-DE\"}]},\"last_name\":{\"display\":[{\"name\":\"Surname\",\"locale\":\"en-US\"},{\"name\":\"Nachname\",\"locale\":\"de-DE\"}]},\"email\":{},\"phone_number\":{},\"address\":{\"street_address\":{},\"locality\":{},\"region\":{},\"country\":{}},\"birthdate\":{},\"is_over_18\":{},\"is_over_21\":{},\"is_over_65\":{}}}}}}"; private const string AuthServerMetadataWithDpop = "{\"issuer\":\"https://issuer.io\",\"token_endpoint\":\"https://issuer.io/token\",\"token_endpoint_auth_methods_supported\":[\"urn:ietf:params:oauth:client-assertion-type:verifiable-presentation\"],\"response_types_supported\":[\"urn:ietf:params:oauth:grant-type:pre-authorized_code\"],\"dpop_signing_alg_values_supported\":[\"ES256\"]}\n"; @@ -97,17 +97,14 @@ public class Oid4VciClientServiceTests { CredentialIssuer = "https://issuer.io", CredentialEndpoint = "https://issuer.io/credential", - CredentialsSupported = new Dictionary + CredentialConfigurationsSupported = new Dictionary { { "VerifiedEmail", new OidCredentialMetadata { Format = "vc+sdjwt", - CredentialDefinition = new OidCredentialDefinition - { - Vct = Vct, - Claims = new Dictionary() - } + Vct = Vct, + Claims = new Dictionary() } } } @@ -130,7 +127,7 @@ public async Task CanRequestCredentialWithoutDPopAsync() //Act var actualCredentialResponse = await _oid4VciClientService.RequestCredentialAsync( - _oidIssuerMetadata.CredentialsSupported.First().Value, + _oidIssuerMetadata.CredentialConfigurationsSupported.First().Value, _oidIssuerMetadata, PreAuthorizedCode, TransactionCode, @@ -169,7 +166,7 @@ public async Task CanRequestCredentialWithDPoPAsync() //Act var actualCredentialResponse = await _oid4VciClientService.RequestCredentialAsync( - _oidIssuerMetadata.CredentialsSupported.First().Value, + _oidIssuerMetadata.CredentialConfigurationsSupported.First().Value, _oidIssuerMetadata, PreAuthorizedCode, TransactionCode, diff --git a/test/Hyperledger.Aries.Tests/Integration/Oid4VpClientServiceTests.cs b/test/Hyperledger.Aries.Tests/Integration/Oid4VpClientServiceTests.cs index 91ce311c..930b8b63 100644 --- a/test/Hyperledger.Aries.Tests/Integration/Oid4VpClientServiceTests.cs +++ b/test/Hyperledger.Aries.Tests/Integration/Oid4VpClientServiceTests.cs @@ -92,17 +92,14 @@ public Oid4VpClientServiceTests() { CredentialIssuer = "https://issuer.io", CredentialEndpoint = "https://issuer.io/credential", - CredentialsSupported = new Dictionary + CredentialConfigurationsSupported = new Dictionary() { { "VerifiedEmail", new OidCredentialMetadata { Format = "vc+sdjwt", - CredentialDefinition = new OidCredentialDefinition - { - Vct = Vct, - Claims = new Dictionary() - } + Vct = Vct, + Claims = new Dictionary() } } }