### Branch Naming Convention Examples Source: https://github.com/eu-digital-identity-wallet/eudi-lib-jvm-sdjwt-kt/blob/main/CONTRIBUTING.md Use a consistent naming convention for your branches, starting with a type (feat, fix, docs, style, refactor, test, chore) followed by a short description. ```text feat/add-new-button fix/typo-in-readme docs/update-contributing-guide style/format-code refactor/extract-method test/add-unit-tests chore/update-dependencies ``` -------------------------------- ### SD-JWT VC Verification Example Source: https://github.com/eu-digital-identity-wallet/eudi-lib-jvm-sdjwt-kt/blob/main/README.md Demonstrates how to verify an SD-JWT VC using the SdJwtVcVerifier. Requires Nimbus JOSE+JWT and the optional Tink dependency for OctetKeyPair support. ```kotlin val sdJwtVcVerification = runBlocking { val issuer = Url("https://issuer.example.com") with(NimbusSdJwtOps) { val sdJwt = run { val spec = sdJwt { claim(RFC7519.ISSUER, issuer.toString()) claim(SdJwtVcSpec.VCT, "urn:credential:sample") } val signer = issuer(signer = ECDSASigner(issuerEcKeyPairWithCertificate), signAlgorithm = JWSAlgorithm.ES512) { type(JOSEObjectType(SdJwtVcSpec.MEDIA_SUBTYPE_DC_SD_JWT)) x509CertChain(issuerEcKeyPairWithCertificate.x509CertChain) } signer.issue(spec).getOrThrow().serialize() } val verifier = SdJwtVcVerifier( issuerVerificationMethod = IssuerVerificationMethod.usingX5c { chain, _ -> chain.first().base64 == issuerEcKeyPairWithCertificate.x509CertChain.first() }, typeMetadataPolicy = TypeMetadataPolicy.NotUsed, null, ) verifier.verify(sdJwt) } } ``` -------------------------------- ### Example JSON Claims Source: https://github.com/eu-digital-identity-wallet/eudi-lib-jvm-sdjwt-kt/blob/main/Module.md The resulting JSON object after recreating claims from an SD-JWT, showing both always-disclosed and selectively disclosable claims. ```json { "sub": "6c5c0a49-b589-431d-bae7-219122a9ec2c", "address": { "street_address": "Schulstr. 12", "locality": "Schulpforta", "region": "Sachsen-Anhalt", "country": "DE" }, "iss": "https://example.com/issuer", "exp": 1735689661, "iat": 1516239022 } ``` -------------------------------- ### Issue SD-JWT with Claims and Structured Disclosure Source: https://github.com/eu-digital-identity-wallet/eudi-lib-jvm-sdjwt-kt/blob/main/README.md Use the SD-JWT DSL to define claims, including structured disclosure for specific fields like 'address'. This example demonstrates issuing an SD-JWT signed with an RSA key pair. ```kotlin import com.nimbusds.jose.JWSAlgorithm import com.nimbusds.jose.crypto.ECDSASigner import eu.europa.ec.eudi.sdjwt.* import eu.europa.ec.eudi.sdjwt.NimbusSdJwtOps import eu.europa.ec.eudi.sdjwt.dsl.values.sdJwt import kotlinx.coroutines.runBlocking val issuedSdJwt: String = runBlocking { val sdJwtSpec = sdJwt { claim("sub", "6c5c0a49-b589-431d-bae7-219122a9ec2c") claim("iss", "https://example.com/issuer") claim("iat", 1516239022) claim("exp", 1735689661) objClaim("address") { sdClaim("street_address", "Schulstr. 12") sdClaim("locality", "Schulpforta") sdClaim("region", "Sachsen-Anhalt") sdClaim("country", "DE") } } with(NimbusSdJwtOps) { val issuer = issuer(signer = ECDSASigner(issuerEcKeyPair), signAlgorithm = JWSAlgorithm.ES256) issuer.issue(sdJwtSpec).getOrThrow().serialize() } } ``` -------------------------------- ### Fold Disclosable Structures in Kotlin Source: https://github.com/eu-digital-identity-wallet/eudi-lib-jvm-sdjwt-kt/blob/main/docs/dsl.md Traverses and accumulates values from disclosable structures. This example collects all selectively disclosed claim names. ```kotlin val disclosedClaimNames = sdJwtSpec.fold( objectHandlers = customObjectHandlers, arrayHandlers = customArrayHandlers, combine = { acc, current -> acc + current }, ) ``` -------------------------------- ### Recreate Original SD-JWT Claims Source: https://github.com/eu-digital-identity-wallet/eudi-lib-jvm-sdjwt-kt/blob/main/README.md Recreates the original claims from an SD-JWT, replacing digests with their corresponding selectively disclosable claims. Requires necessary imports and an issuer setup. ```kotlin import com.nimbusds.jose.JWSAlgorithm import com.nimbusds.jose.crypto.RSASSASigner import com.nimbusds.jwt.SignedJWT import eu.europa.ec.eudi.sdjwt.* import eu.europa.ec.eudi.sdjwt.dsl.values.sdJwt import kotlinx.coroutines.runBlocking import kotlinx.serialization.json.JsonObject ``` ```kotlin val claims: JsonObject = runBlocking { val sdJwt: SdJwt = run { val spec = sdJwt { claim("sub", "6c5c0a49-b589-431d-bae7-219122a9ec2c") claim("iss", "https://example.com/issuer") claim("iat", 1516239022) claim("exp", 1735689661) objClaim("address") { sdClaim("street_address", "Schulstr. 12") sdClaim("locality", "Schulpforta") sdClaim("region", "Sachsen-Anhalt") sdClaim("country", "DE") } } val issuer = NimbusSdJwtOps.issuer(signer = RSASSASigner(issuerRsaKeyPair), signAlgorithm = JWSAlgorithm.RS256) issuer.issue(spec).getOrThrow() } with(NimbusSdJwtOps) { sdJwt.recreateClaimsAndDisclosuresPerClaim().first } } ``` -------------------------------- ### Add eudi-lib-jvm-sdjwt-kt to build.gradle.kts Source: https://github.com/eu-digital-identity-wallet/eudi-lib-jvm-sdjwt-kt/blob/main/README.md Include the library in your project's dependencies by adding the provided line to your build.gradle.kts file. ```gradle dependencies { implementation("eu.europa.ec.euidw:eudi-lib-jvm-sdjwt-kt:$version") } ``` -------------------------------- ### Access Claim Display Information Source: https://github.com/eu-digital-identity-wallet/eudi-lib-jvm-sdjwt-kt/blob/main/docs/dsl.md Retrieve and display information for UI rendering from claim metadata. This includes language, name, and description for each display entry. ```kotlin // Access display information for a claim val displayInfo = attributeMetadata.display if (displayInfo != null) { for (display in displayInfo) { println("Language: ${display.lang}") println("Name: ${display.name}") println("Description: ${display.description}") } } ``` -------------------------------- ### Create SD-JWT Verifiable Credential Data Model v2.0 Source: https://github.com/eu-digital-identity-wallet/eudi-lib-jvm-sdjwt-kt/blob/main/docs/examples/example-sd-jwt-vc-data-v02-01.md This snippet demonstrates how to construct a Verifiable Credential Data Model v2.0 using the SD-JWT Kotlin DSL. It includes various claims, some of which are selectively disclosed. ```kotlin val sdJwtVcDataV2 = sdJwt { arrClaim("@context") { claim("https://www.w3.org/2018/credentials/v1") claim("https://w3id.org/vaccination/v1") } arrClaim("type") { claim("VerifiableCredential") claim("VaccinationCertificate") } claim("issuer", "https://example.com/issuer") claim("issuanceDate", "2023-02-09T11:01:59Z") claim("expirationDate", "2028-02-08T11:01:59Z") claim("name", "COVID-19 Vaccination Certificate") claim("description", "COVID-19 Vaccination Certificate") objClaim("cnf") { objClaim("jwk") { claim("kty", "EC") claim("crv", "P-256") claim("x", "TCAER19Zvu3OHF4j4W4vfSVoHIP1ILilDls7vCeGemc") claim("y", "ZxjiWWbZMQGHVWKVQ4hbSIirsVfuecCE6t4jT9F2HZQ") } } objClaim("credentialSubject") { claim("type", "VaccinationEvent") sdClaim("nextVaccinationDate", "2021-08-16T13:40:12Z") sdClaim("countryOfVaccination", "GE") sdClaim("dateOfVaccination", "2021-06-23T13:40:12Z") sdClaim("order", "3/3") sdClaim("administeringCentre", "Praxis Sommergarten") sdClaim("batchNumber", "1626382736") sdClaim("healthProfessional", "883110000015376") objClaim("vaccine") { claim("type", "Vaccine") sdClaim("atcCode", "J07BX03") sdClaim("medicinalProductName", "COVID-19 Vaccine Moderna") sdClaim("marketingAuthorizationHolder", "Moderna Biotech") } objClaim("recipient") { claim("type", "VaccineRecipient") sdClaim("gender", "Female") sdClaim("birthDate", "1961-08-17") sdClaim("givenName", "Marion") sdClaim("familyName", "Mustermann") } } } ``` ```json { "@context": [ "https://www.w3.org/2018/credentials/v1", "https://w3id.org/vaccination/v1" ], "type": [ "VerifiableCredential", "VaccinationCertificate" ], "issuer": "https://example.com/issuer", "issuanceDate": "2023-02-09T11:01:59Z", "expirationDate": "2028-02-08T11:01:59Z", "name": "COVID-19 Vaccination Certificate", "description": "COVID-19 Vaccination Certificate", "cnf": { "jwk": { "kty": "EC", "crv": "P-256", "x": "TCAER19Zvu3OHF4j4W4vfSVoHIP1ILilDls7vCeGemc", "y": "ZxjiWWbZMQGHVWKVQ4hbSIirsVfuecCE6t4jT9F2HZQ" } }, "credentialSubject": { "type": "VaccinationEvent", "_sd": [ "AN8fGQH71sxVicG6kpzMeuC6DUjWYweTbzo2YENbPIw", "W7PJCiGTkD6698JubYrfE9Nw0s9s2Qufo_w-rbGglso", "3NQAz_q5LUUdLssevda4iAVyHFQXrIr8azIxD1pzVF4", "hwSSXnJOxODS4g0272WSRvyfBUaI7gEFb-bgiQE4Pv8", "ew2bZj2drxmdWsDLgAgORgAflpO_MjwJ6BqRyyMfAiA", "MXrkHIROu1-CUMqgTmpJApw1QKiG-Ev4E3BlMI8dLOs", "kmq2TibfEvdQ59sv6rzINltNqvpJfOG1VmLl3gMZseg" ], "vaccine": { "type": "Vaccine", "_sd": [ "jc7VUrPqLJ1uCF3jo0U5eMsMl2sdtjEf2k2J2GML3lo", "NnweRuqvhENsc-yYOVa7tBSXnmwn8v4Y3d00cC1M6hI", "-aWn6C2F8nsfTQEpMotE0D0YsLN6XRCYwlKazyBGxgk" ] }, "recipient": { "type": "VaccineRecipient", "_sd": [ "Ck24z45Hi1vUfNt44qKLmS1gnbRqPvmSmyMaW9otpbU", "A7jZlA13I-9fbqydsUE1zprrw9GVW17q9JgYgru4VcQ", "pTPGEA7YCTuIGF2uEiykOSLE7e9QHtk1-dw6PKd1A_w", "YXlycX6aWB5LGdyhdaH-rq_ze34ALbh4FyVwkpuf4n0" ] } }, "_sd_alg": "sha-256" } ``` ```json [ ["...salt...","nextVaccinationDate","2021-08-16T13:40:12Z"], ["...salt...","countryOfVaccination","GE"], ["...salt...","dateOfVaccination","2021-06-23T13:40:12Z"], ["...salt...","order","3/3"], ["...salt...","administeringCentre","Praxis Sommergarten"], ["...salt...","batchNumber","1626382736"], ["...salt...","healthProfessional","883110000015376"], ["...salt...","atcCode","J07BX03"], ["...salt...","medicinalProductName","COVID-19 Vaccine Moderna"], ["...salt...","marketingAuthorizationHolder","Moderna Biotech"], ["...salt...","gender","Female"], ["...salt...","birthDate","1961-08-17"], ["...salt...","givenName","Marion"], ["...salt...","familyName","Mustermann"] ] ``` -------------------------------- ### Create Basic SD-JWT Source: https://github.com/eu-digital-identity-wallet/eudi-lib-jvm-sdjwt-kt/blob/main/docs/dsl.md Construct a basic SD-JWT with standard claims like subject, issuer, issued at, expiration, and selectively disclosed personal information (given name, family name, email). ```kotlin val sdJwtSpec = sdJwt { claim("sub", "6c5c0a49-b589-431d-bae7-219122a9ec2c") claim("iss", "https://example.com/issuer") claim("iat", 1516239022) claim("exp", 1735689661) sdClaim("given_name", "John") sdClaim("family_name", "Doe") sdClaim("email", "john.doe@example.com") } ``` -------------------------------- ### Generate Credential UI Components Source: https://github.com/eu-digital-identity-wallet/eudi-lib-jvm-sdjwt-kt/blob/main/docs/dsl.md Automatically generate UI components for displaying a credential based on its content and associated SD-JWT VC metadata. This simplifies UI development for credential presentation. ```kotlin // Generate UI components for displaying a credential val uiComponents = generateCredentialUI(credential, sdJwtVcMetadata) ``` -------------------------------- ### Create Simple SD-JWT with Claims Source: https://github.com/eu-digital-identity-wallet/eudi-lib-jvm-sdjwt-kt/blob/main/docs/dsl.md Use the `sdJwt` function to create a JSON-based SD-JWT structure. Claims added with `claim()` are always disclosed, while those added with `sdClaim()` are selectively disclosed. ```kotlin val sdJwtSpec = sdJwt { // Always disclosed claims (included directly in the JWT) claim("sub", "6c5c0a49-b589-431d-bae7-219122a9ec2c") claim("iss", "https://example.com/issuer") claim("iat", 1516239022) claim("exp", 1735689661) // Selectively disclosed claims (included as disclosure digests) sdClaim("given_name", "John") sdClaim("family_name", "Doe") } ``` -------------------------------- ### Create SD-JWT Verifiable Credential in Kotlin Source: https://github.com/eu-digital-identity-wallet/eudi-lib-jvm-sdjwt-kt/blob/main/docs/examples/example-sd-jwt-vc-01.md Use the `sdJwt` DSL to construct a Verifiable Credential with standard and selectively disclosed claims. Ensure necessary imports are present. ```kotlin import eu.europa.ec.eudi.sdjwt.dsl.values.sdJwt val sdJwtVc = sdJwt { claim("iss", "https://issuer.example.com") claim("iat", 1683000000) claim("exp", 1883000000) claim("vct", "https://bmi.bund.example/credential/pid/1.0") objClaim("cnf") { objClaim("jwk") { claim("kty", "EC") claim("crv", "P-256") claim("x", "TCAER19Zvu3OHF4j4W4vfSVoHIP1ILilDls7vCeGemc") claim("y", "ZxjiWWbZMQGHVWKVQ4hbSIirsVfuecCE6t4jT9F2HZQ") } } sdClaim("given_name", "Erika") sdClaim("family_name", "Mustermann") sdClaim("birthdate", "1963-08-12") sdClaim("source_document_type", "id_card") sdArrClaim("nationalities") { claim("DE") } sdClaim("gender", "female") sdClaim("birth_family_name", "Gabler") sdClaim("also_known_as", "Schwester") sdObjClaim("address") { sdClaim("street_address", "Heidestraße 17") sdClaim("locality", "Köln") sdClaim("postal_code", "51147") sdClaim("country", "DE") } sdObjClaim("place_of_birth") { claim("country", "DE") sdClaim("locality", "Berlin") } objClaim("age_equal_or_over") { sdClaim("12", true) sdClaim("14", true) sdClaim("16", true) sdClaim("18", true) sdClaim("21", true) sdClaim("65", false) } } ``` ```json { "iss": "https://issuer.example.com", "iat": 1683000000, "exp": 1883000000, "vct": "https://bmi.bund.example/credential/pid/1.0", "cnf": { "jwk": { "kty": "EC", "crv": "P-256", "x": "TCAER19Zvu3OHF4j4W4vfSVoHIP1ILilDls7vCeGemc", "y": "ZxjiWWbZMQGHVWKVQ4hbSIirsVfuecCE6t4jT9F2HZQ" } }, "_sd": [ "eO_HA4ixR8-HtnCIexytyrg9YoIv1_f2JBBvoeURT4U", "UhB7COWXQpF6BQXOF5T2dSHAZEn4eQbL6ljmte0T3ig", "Cz4sgRSQNxQPMFOTQX-udUqRXXwUC39PzFyCfXxmjos", "jtA1gYLu-j9BUCTBZOz2scCYtcWTM48ZbYupoB8WK-g", "JcDLTp8dgP_DxWDjdHiqZ3PZy62Ue9A58Y6mx-L8wMQ", "X1Oj6ZxK44W1sKTRXEltMeAvF0zzkHkqpGgR620mKNY", "eK0doYXEPQ2HuGOkfQybV4hsa85yXRvysNq5j5BQ-_Y", "oM31EdZdrBS6FwbgqhgyPb0ZEkySUhtiAlBCSUPWc1w", "-AolJEEv-Q1oWNPJ3PUpC9vo8wuAohxO2jEb7PwLRyA", "PU-PF8t1qdcyyE71KYaOo_CXN67kZoZMnVpImadVqRI" ], "age_equal_or_over": { "_sd": [ "hCETIFvt0REVh9eR9eTSggLxGS-x9Xk5RolLINs9B6k", "HnkQfo5UceT71ygJ5VFZBWBCKSYUm2zzNVrTQ6F6Trk", "gPSU6dRniTHF3ERLx8-BdZVUAMJE49WpZ4wovKZNZpI", "e8jBCC_A0FLS9wsXPqaXpi2MWQ0iHsbsSAP5S99zFqc", "hSO06ko_FY1zKcxhkzk1B5GW15sJWF2HCeGj2OSICPk", "Hxi2pax1gFZY0CU2VPMMJFsMG32YNbVEA9s_wNcQJJ8" ] }, "_sd_alg": "sha-256" } ``` ```json [ ["...salt...","given_name","Erika"], ["...salt...","family_name","Mustermann"], ["...salt...","birthdate","1963-08-12"], ["...salt...","source_document_type","id_card"], ["...salt...","nationalities",["DE"]], ["...salt...","gender","female"], ["...salt...","birth_family_name","Gabler"], ["...salt...","also_known_as","Schwester"], ["...salt...","street_address","Heidestraße 17"], ["...salt...","locality","Köln"], ["...salt...","postal_code","51147"], ["...salt...","country","DE"], ["...salt...","address",{"_sd":["0SqBd-P2pU7bEcaEF7JHSrM_uZUXr4ZDO2p0lEFpB30","PXDyvcQ3-3eeJLfYKWIbeO2Pm4dUjTVW9w0jC7zFyUw","6YonldXmAaSSIV7HpttlHqAtG71DN-dzLr7thT3xNr4","XWilRh55_L3EzKY0VeXa0FFJb5nuzknE2iBV_Zdhh4w"]}], ["...salt...","locality","Berlin"], ["...salt...","place_of_birth",{"country":"DE","_sd":["242Ck5tIKgGYuKojAtIt9sLnqrWsNr3Gnj1g2RPc3Vw"]}], ["...salt...","12",true], ["...salt...","14",true], ["...salt...","16",true], ["...salt...","18",true], ["...salt...","21",true], ["...salt...","65",false] ] ``` -------------------------------- ### Create SD-JWT Presentation with Specific Claims Source: https://github.com/eu-digital-identity-wallet/eudi-lib-jvm-sdjwt-kt/blob/main/Module.md As a Holder, create a presentation of an SD-JWT, selectively disclosing specific claims using Claim Paths. This requires the original issued SD-JWT. ```kotlin val presentationSdJwt: SdJwt = runBlocking { with(NimbusSdJwtOps) { val issuedSdJwt = run { val sdJwtSpec = sdJwt { claim("sub", "6c5c0a49-b589-431d-bae7-219122a9ec2c") claim("iss", "https://example.com/issuer") claim("iat", 1516239022) claim("exp", 1735689661) sdObjClaim("address") { sdClaim("street_address", "Schulstr. 12") sdClaim("locality", "Schulpforta") sdClaim("region", "Sachsen-Anhalt") sdClaim("country", "DE") } } val issuer = issuer(signer = RSASSASigner(issuerRsaKeyPair), signAlgorithm = JWSAlgorithm.RS256) issuer.issue(sdJwtSpec).getOrThrow() } val addressPath = ClaimPath.claim("address") val claimsToInclude = setOf(addressPath.claim("region"), addressPath.claim("country")) issuedSdJwt.present(claimsToInclude)!! } } ``` -------------------------------- ### Commit and push changes Source: https://github.com/eu-digital-identity-wallet/eudi-lib-jvm-sdjwt-kt/blob/main/CONTRIBUTING.md After making code modifications, stage all changes, commit them with a descriptive message, and push the branch to your forked repository. ```bash git add . git commit -m "Add a new feature" git push origin my-branch ``` -------------------------------- ### Create a new branch for changes Source: https://github.com/eu-digital-identity-wallet/eudi-lib-jvm-sdjwt-kt/blob/main/CONTRIBUTING.md Follow the GitHub Flow by creating a new branch from the main branch for your contributions. Ensure you pull the latest changes before branching. ```bash git checkout main git pull git checkout -b my-branch ``` -------------------------------- ### Create SD-JWT with Structured Address Claim Source: https://github.com/eu-digital-identity-wallet/eudi-lib-jvm-sdjwt-kt/blob/main/docs/examples/example-handling-structure-claims-01.md Use the `sdJwt` builder to define a JWT with a structured 'address' claim. This allows individual members of the address to be selectively disclosed. Ensure necessary imports are present. ```kotlin import eu.europa.ec.eudi.sdjwt.dsl.values.sdJwt val handlingStructuredClaims = sdJwt { claim("iss", "https://issuer.example.com") claim("iat", 1683000000) claim("exp", 1883000000) sdClaim("sub", "6c5c0a49-b589-431d-bae7-219122a9ec2c") sdClaim("given_name", "太郎") sdClaim("family_name", "山田") sdClaim("email", "\"unusual email address\"@example.jp") sdClaim("phone_number", "+81-80-1234-5678") sdClaim("birthdate", "1940-01-01") objClaim("address") { sdClaim("street_address", "東京都港区芝公園4丁目2−8") sdClaim("locality", "東京都") sdClaim("region", "港区") sdClaim("country", "JP") } } ``` -------------------------------- ### Create Flat SD-JWT with Kotlinx Serialization DSL Source: https://github.com/eu-digital-identity-wallet/eudi-lib-jvm-sdjwt-kt/blob/main/docs/examples/example-flat-sd-jwt-01.md Use the sdJwt builder to construct a Flat SD-JWT. The 'address' claim is nested within an sdObjClaim, indicating it will be disclosed as a single unit. ```kotlin import eu.europa.ec.eudi.sdjwt.dsl.values.sdJwt val flatSdJwt = sdJwt { claim("iss", "https://issuer.example.com") claim("iat", 1683000000) claim("exp", 1883000000) claim("sub", "6c5c0a49-b589-431d-bae7-219122a9ec2c") sdObjClaim("address") { claim("street_address", "Schulstr. 12") claim("locality", "Schulpforta") claim("region", "Sachsen-Anhalt") claim("country", "DE") } } ``` -------------------------------- ### Create Structured SD-JWT with Kotlin DSL Source: https://github.com/eu-digital-identity-wallet/eudi-lib-jvm-sdjwt-kt/blob/main/docs/examples/example-structured-sd-jwt-01.md Use the `sdJwt` builder from the Kotlinx Serialization DSL to construct a SD-JWT. This method allows defining standard claims and nested claims that can be selectively disclosed. ```kotlin import eu.europa.ec.eudi.sdjwt.dsl.values.sdJwt val structuredSdJwt = sdJwt { claim("iss", "https://issuer.example.com") claim("iat", 1683000000) claim("exp", 1883000000) claim("sub", "6c5c0a49-b589-431d-bae7-219122a9ec2c") objClaim("address") { sdClaim("street_address", "Schulstr. 12") sdClaim("locality", "Schulpforta") sdClaim("region", "Sachsen-Anhalt") sdClaim("country", "DE") } } ``` -------------------------------- ### Verify SD-JWT Presentation Source: https://github.com/eu-digital-identity-wallet/eudi-lib-jvm-sdjwt-kt/blob/main/Module.md Verifies a serialized SD-JWT presentation. The verifier needs the issuer's public key and signing algorithm. Key binding verification requires holder's public key information. ```kotlin val verifiedPresentationSdJwt: SdJwt = runBlocking { with(NimbusSdJwtOps) { val jwtSignatureVerifier = RSASSAVerifier(issuerRsaKeyPair).asJwtVerifier() val unverifiedPresentationSdJwt = serializedUnverifiedPresentationSdJwt verify( jwtSignatureVerifier, unverifiedPresentationSdJwt, ).getOrThrow() } } ``` -------------------------------- ### Build SD-JWT Object with Definition Source: https://github.com/eu-digital-identity-wallet/eudi-lib-jvm-sdjwt-kt/blob/main/README.md Build SD-JWT objects using a predefined SdJwtDefinition as a template. This automatically handles selective disclosure and transforms raw JSON data. ```kotlin val sdJwtObject = sdJwtVc(sdJwtDefinition) { put("given_name", "John") put("family_name", "Doe") // Additional claims... }.getOrThrow() ``` -------------------------------- ### Manually Construct SdJwtObject in Kotlin Source: https://github.com/eu-digital-identity-wallet/eudi-lib-jvm-sdjwt-kt/blob/main/docs/dsl.md Manually constructs an SdJwtObject, demonstrating the equivalent of template-based generation. This approach requires explicit calls for each claim and selective disclosure marking. ```kotlin val manuallyBuiltSdJwtObject = sdJwt { claim(SdJwtVcSpec.VCT, PidDefinition.metadata.vct.value) // Manually add vct sdClaim("given_name", "Foo") // Manually mark as SD sdClaim("family_name", "Bar") // Manually mark as SD sdArrClaim("nationalities") { // Manually mark array as SD, then its elements sdClaim("GR") } sdObjClaim("age_equal_or_over") { // Manually mark object as SD sdClaim("18", true) // Manually mark inner claim as SD } sdObjClaim("address") { // Manually mark object as SD sdClaim("country", "GR") // Manually mark inner claim as SD sdClaim("street_address", "12345 Main Street") // Manually mark inner claim as SD } } ``` -------------------------------- ### Configure Minimum Decoy Digests in SD-JWT Source: https://github.com/eu-digital-identity-wallet/eudi-lib-jvm-sdjwt-kt/blob/main/README.md Configures an SD-JWT to include a minimum number of decoy digests within its digest arrays. This is achieved using the `minimumDigests` parameter in the DSL for various claim types. ```kotlin import eu.europa.ec.eudi.sdjwt.* import eu.europa.ec.eudi.sdjwt.dsl.values.sdJwt ``` ```kotlin val sdJwtWithMinimumDigests = sdJwt(minimumDigests = 5) { // This 5 guarantees that at least 5 digests will be found // to the digest array, regardless of the content of the SD-JWT objClaim("address", minimumDigests = 10) { // This affects the nested array of the digests that will // have at list 10 digests. } sdObjClaim("address1", minimumDigests = 8) { // This will affect the digests array that will be found // in the disclosure of this recursively disclosable item // the whole object will be embedded in its parent // as a single digest } arrClaim("evidence", minimumDigests = 2) { // Array will have at least 2 digests // regardless of its elements } sdArrClaim("evidence1", minimumDigests = 2) { // Array will have at least 2 digests // regardless of its elements // the whole array will be embedded in its parent // as a single digest } } ``` -------------------------------- ### Create Complex Structured SD-JWT Source: https://github.com/eu-digital-identity-wallet/eudi-lib-jvm-sdjwt-kt/blob/main/docs/examples/example-complex-structured-sd-jwt-01.md Use the `sdJwt` builder to construct a complex SD-JWT with nested claims and selectively disclosed fields. This is useful for representing detailed verifiable credentials. ```kotlin val complexStructuredSdJwt = sdJwt { claim("iss", "https://issuer.example.com") claim("iat", 1683000000) claim("exp", 1883000000) objClaim("verified_claims") { objClaim("verification") { sdClaim("time", "2012-04-23T18:25Z") sdClaim("verification_process", "f24c6f-6d3f-4ec5-973e-b0d8506f3bc7") claim("trust_framework", "de_aml") arrClaim("evidence") { sdObjClaim { sdClaim("type", "document") sdClaim("method", "pipp") sdClaim("time", "2012-04-22T11:30Z") sdObjClaim("document") { claim("type", "idcard") objClaim("issuer") { claim("name", "Stadt Augsburg") claim("country", "DE") } claim("number", "53554554") claim("date_of_issuance", "2010-03-23") claim("date_of_expiry", "2020-03-22") } } } } objClaim("claims") { sdClaim("given_name", "Max") sdClaim("family_name", "Müller") sdArrClaim("nationalities") { claim("DE") } sdClaim("birthdate", "1956-01-28") sdObjClaim("place_of_birth") { claim("country", "IS") claim("locality", "Þykkvabæjarklaustur") } sdObjClaim("address") { claim("locality", "Maxstadt") claim("postal_code", "12344") claim("country", "DE") claim("street_address", "Weidenstraße 22") } } sdClaim("birth_middle_name", "Timotheus") sdClaim("salutation", "Dr.") sdClaim("msisdn", "49123456789") } } ``` -------------------------------- ### Create SD-JWT Object Definition from Metadata in Kotlin Source: https://github.com/eu-digital-identity-wallet/eudi-lib-jvm-sdjwt-kt/blob/main/docs/dsl.md Creates an SD-JWT object definition from SD-JWT VC metadata. This converts flat metadata into a hierarchical disclosable structure. ```kotlin val sdJwtDefinition = SdJwtDefinition.fromSdJwtVcMetadataStrict( sdJwtVcMetadata = resolvedTypeMetadata, selectivelyDiscloseWhenAllowed = true ) ``` -------------------------------- ### Create SD-JWT with Recursive Disclosures in Kotlin Source: https://github.com/eu-digital-identity-wallet/eudi-lib-jvm-sdjwt-kt/blob/main/docs/examples/example-recursive-sd-jwt-01.md Use the `sdJwt` builder to define claims and recursively disclosable objects. This is useful when you need to selectively disclose not only entire objects but also their individual properties. ```kotlin import eu.europa.ec.eudi.sdjwt.dsl.values.sdJwt val recursiveSdJwt = sdJwt { claim("iss", "https://issuer.example.com") claim("iat", 1683000000) claim("exp", 1883000000) claim("sub", "6c5c0a49-b589-431d-bae7-219122a9ec2c") sdObjClaim("address") { sdClaim("street_address", "Schulstr. 12") sdClaim("locality", "Schulpforta") sdClaim("region", "Sachsen-Anhalt") sdClaim("country", "DE") } } ``` -------------------------------- ### Create SD-JWT with Nested Objects Source: https://github.com/eu-digital-identity-wallet/eudi-lib-jvm-sdjwt-kt/blob/main/docs/dsl.md Construct nested objects within an SD-JWT. Use `objClaim()` for objects where properties can have mixed disclosure, and `sdObjClaim()` for entire objects that are selectively disclosed as a single unit. ```kotlin val sdJwtSpec = sdJwt { // Regular claims claim("sub", "6c5c0a49-b589-431d-bae7-219122a9ec2c") // Object with selectively disclosed properties objClaim("address") { sdClaim("street_address", "Schulstr. 12") sdClaim("locality", "Schulpforta") sdClaim("region", "Sachsen-Anhalt") sdClaim("country", "DE") } // Selectively disclosed object (the entire object is disclosed as one unit) sdObjClaim("credentials") { claim("degree", "Bachelor of Science") claim("field", "Computer Science") } } ``` -------------------------------- ### Create SD-JWT with Structured Address Disclosure Source: https://github.com/eu-digital-identity-wallet/eudi-lib-jvm-sdjwt-kt/blob/main/docs/dsl.md Build an SD-JWT that includes a structured address claim, where the address itself is an object containing selectively disclosed street, locality, region, and country. ```kotlin val sdJwtSpec = sdJwt { claim("sub", "6c5c0a49-b589-431d-bae7-219122a9ec2c") claim("iss", "https://example.com/issuer") sdObjClaim("address") { sdClaim("street_address", "Schulstr. 12") sdClaim("locality", "Schulpforta") sdClaim("region", "Sachsen-Anhalt") sdClaim("country", "DE") } } ``` -------------------------------- ### Create Complex SD-JWT with Arrays and Nested Objects Source: https://github.com/eu-digital-identity-wallet/eudi-lib-jvm-sdjwt-kt/blob/main/docs/dsl.md Use the `sdJwt` builder to define claims, including nested objects and arrays of strings or objects. This is useful for representing structured credential data. ```kotlin val sdJwtSpec = sdJwt { claim("sub", "6c5c0a49-b589-431d-bae7-219122a9ec2c") claim("iss", "https://example.com/issuer") sdObjClaim("personal_info") { sdClaim("given_name", "John") sdClaim("family_name", "Doe") sdArrClaim("nationalities") { claim("US") claim("DE") } } sdObjClaim("education") { sdArrClaim("degrees") { objClaim { claim("degree", "Bachelor") claim("field", "Computer Science") claim("year", 2015) } objClaim { claim("degree", "Master") claim("field", "Data Science") claim("year", 2017) } } } } ``` -------------------------------- ### Create SD-JWT with Arrays Source: https://github.com/eu-digital-identity-wallet/eudi-lib-jvm-sdjwt-kt/blob/main/docs/dsl.md Incorporate arrays into SD-JWTs. Use `arrClaim()` for arrays with mixed disclosure elements, and `sdArrClaim()` for entire arrays that are selectively disclosed as a single unit. ```kotlin val sdJwtSpec = sdJwt { // Regular array with mixed disclosure elements arrClaim("nationalities") { claim("US") sdClaim("DE") } // Selectively disclosed array (the entire array is disclosed as one unit) sdArrClaim("languages") { claim("en") claim("de") } } ``` -------------------------------- ### SD-JWT with Minimum Digests and Decoys Source: https://github.com/eu-digital-identity-wallet/eudi-lib-jvm-sdjwt-kt/blob/main/docs/dsl.md Enhance privacy by specifying a minimum number of digests for the top-level object or nested objects using the `minimumDigests` parameter. The library adds decoy digests if the actual number of selectively disclosed elements is less than the minimum. ```kotlin val sdJwtSpec = sdJwt(minimumDigests = 5) { // This ensures at least 5 digests in the top-level object objClaim("address", minimumDigests = 3) { // This ensures at least 3 digests in the address object sdClaim("street_address", "Schulstr. 12") sdClaim("country", "DE") } } ``` -------------------------------- ### Generate SdJwtObject from Raw JSON using Definition Template in Kotlin Source: https://github.com/eu-digital-identity-wallet/eudi-lib-jvm-sdjwt-kt/blob/main/docs/dsl.md Generates an SdJwtObject directly from raw JSON data using an SdJwtDefinition as a template. This simplifies code by automating selective disclosure rules. ```kotlin val sdJwtObjectFromTemplate = sdJwtVc(PidDefinition) { // PidDefinition serves as the template put("given_name", "Foo") put("family_name", "Bar") putJsonArray("nationalities") { add("GR") } putJsonObject("age_equal_or_over") { put("18", true) } putJsonObject("address") { put("country", "GR") put("street_address", "12345 Main Street") } }.getOrThrow() // Ensure proper Result handling ``` -------------------------------- ### Transform SD-JWT to Different Format Source: https://github.com/eu-digital-identity-wallet/eudi-lib-jvm-sdjwt-kt/blob/main/docs/dsl.md Transform an existing SD-JWT credential to a different target format, such as mDL. This process involves mapping the SD-JWT metadata to the target format's metadata requirements. ```kotlin // Transform an SD-JWT to a different format (e.g., mDL) val mdlCredential = sdJwtCredential.transformWithMetadata( targetFormat = CredentialFormat.MDL, metadataMapper = { metadata -> mapSdJwtMetadataToMdl(metadata) } ) ``` -------------------------------- ### Recreate Original SD-JWT Claims Source: https://github.com/eu-digital-identity-wallet/eudi-lib-jvm-sdjwt-kt/blob/main/Module.md Recreates the original claims from an SD-JWT, including selectively disclosable claims. This process replaces digests in the JWT part with the actual claims from disclosures. ```kotlin val claims: JsonObject = runBlocking { val sdJwt: SdJwt = run { val spec = sdJwt { claim("sub", "6c5c0a49-b589-431d-bae7-219122a9ec2c") claim("iss", "https://example.com/issuer") claim("iat", 1516239022) claim("exp", 1735689661) objClaim("address") { sdClaim("street_address", "Schulstr. 12") sdClaim("locality", "Schulpforta") sdClaim("region", "Sachsen-Anhalt") sdClaim("country", "DE") } } val issuer = NimbusSdJwtOps.issuer(signer = RSASSASigner(issuerRsaKeyPair), signAlgorithm = JWSAlgorithm.RS256) issuer.issue(spec).getOrThrow() } with(NimbusSdJwtOps) { sdJwt.recreateClaimsAndDisclosuresPerClaim().first } } ``` -------------------------------- ### Issue SD-JWT with Selective Disclosure Source: https://github.com/eu-digital-identity-wallet/eudi-lib-jvm-sdjwt-kt/blob/main/Module.md Use the SD-JWT DSL to define claims, including selectively disclosable structured claims. Requires an Issuer with a signing key pair. ```kotlin val issuedSdJwt: String = runBlocking { val sdJwtSpec = sdJwt { claim("sub", "6c5c0a49-b589-431d-bae7-219122a9ec2c") claim("iss", "https://example.com/issuer") claim("iat", 1516239022) claim("exp", 1735689661) objClaim("address") { sdClaim("street_address", "Schulstr. 12") sdClaim("locality", "Schulpforta") sdClaim("region", "Sachsen-Anhalt") sdClaim("country", "DE") } } with(NimbusSdJwtOps) { val issuer = issuer(signer = ECDSASigner(issuerEcKeyPair), signAlgorithm = JWSAlgorithm.ES256) issuer.issue(sdJwtSpec).getOrThrow().serialize() } } ``` -------------------------------- ### Verify Issued SD-JWT Source: https://github.com/eu-digital-identity-wallet/eudi-lib-jvm-sdjwt-kt/blob/main/Module.md Verify the signature of an SD-JWT using the Issuer's public key and the signing algorithm. Requires a JWT verifier. ```kotlin val verifiedIssuanceSdJwt: SdJwt = runBlocking { with(NimbusSdJwtOps) { val jwtSignatureVerifier = RSASSAVerifier(issuerRsaKeyPair).asJwtVerifier() val unverifiedIssuanceSdJwt = serializedUnverifiedIssuanceSdJwt verify(jwtSignatureVerifier, unverifiedIssuanceSdJwt).getOrThrow() } } ``` -------------------------------- ### Define Selective Disclosure Policy Source: https://github.com/eu-digital-identity-wallet/eudi-lib-jvm-sdjwt-kt/blob/main/docs/dsl.md Create a selective disclosure policy that marks all Personally Identifiable Information (PII) claims as selectively disclosable. This policy can then be applied when creating an SD-JWT. ```kotlin // Define a policy that makes all PII selectively disclosable val piiPolicy = SelectiveDisclosurePolicy.Builder() .makeSelectivelyDisclosable { metadata -> metadata.isPII } .build() // Apply the policy to create an SD-JWT val sdJwtSpec = createSdJwtWithPolicy(credentialData, piiPolicy) ``` -------------------------------- ### Flat SD-JWT Disclosures Source: https://github.com/eu-digital-identity-wallet/eudi-lib-jvm-sdjwt-kt/blob/main/docs/examples/example-flat-sd-jwt-01.md The disclosures for a Flat SD-JWT contain the salt, the claim name, and the full claim object for each disclosed claim. ```json [ ["...salt...","address",{"street_address":"Schulstr. 12","locality":"Schulpforta","region":"Sachsen-Anhalt","country":"DE"}] ] ``` -------------------------------- ### Map Disclosable Structures in Kotlin Source: https://github.com/eu-digital-identity-wallet/eudi-lib-jvm-sdjwt-kt/blob/main/docs/dsl.md Transforms a disclosable object by applying functions to its keys and values. Use this to modify keys to uppercase and values to strings. ```kotlin val transformedObject = originalObject.map( fK = { key -> key.uppercase() }, // Transform keys to uppercase fA = { value -> value.toString() } // Transform all values to strings ) ```