Present W3C Credential

Using the walt.id verifiable credentials library we can create a verifiable presentation including one or more W3C credentials (v1.1 and v2) in Kotlin/Java.

A verifiable presentation is needed when a holder needs to present one or more credentials to a verifier. Because, as the credential itself holds the issuer's signature, the holder must validate their ownership of the DID specified in the credential's subject by including all requested credentials into a verifiable presentation signed with his key, thereby establishing proof of ownership.

Creating a Verifiable Presentation

Below we are creating a Verifiable Presentation using the PresentationBuilder. We set the DID of the subject, the nonce and add either a JWT-VC or SD-JWT-VC to the presentation using the addCredential or addCredentials if we have more than one.

val vp = PresentationBuilder().apply {
    did = "did:key:123456789"    // sets sub, iss, vp.holder

    /* nbf, iat, jti set automatically to sane default values */

    nonce = "ABC123DEF456GHI789JKL"

    /* vp.context, vp.type, vp.id set automatically to sane default values */

    addCredential(JsonPrimitive(jwtVc)
}

Signing a Verifiable Presentation

Using the PresentationBuilder's sign function, we can turn the Verifiable Presentation into a signed JSON-Web-Token ( JWT-VP) which can be shared with the verifier.

   // Creating Verifiable Presentation
val vp = PresentationBuilder().apply {
    did = "did:key:123456789"

    nonce = "ABC123DEF456GHI789JKL"

    addCredential(JsonPrimitive(jwtVc))
}

// Sign Verifiable Presentation
val vpSigned = vp.buildAndSign(subjectKey)

Signed VP

eyJhbGciOiJFZERTQSIsInR5cCI6IkpXVCIsImtpZCI6ImRpZDprZXk6ejZNa3B1aWhYcW40ajdkbTRxcFMxZVA5TVIyU3Nkb0NGdVdoZFRZRjh6R1V1SEZaI3o2TWtwdWloWHFuNGo3ZG00cXBTMWVQOU1SMlNzZG9DRnVXaGRUWUY4ekdVdUhGWiJ9.eyJzdWIiOiJkaWQ6a2V5Ono2TWtwdWloWHFuNGo3ZG00cXBTMWVQOU1SMlNzZG9DRnVXaGRUWUY4ekdVdUhGWiIsIm5iZiI6MTcwNTQ5MzA0NCwiaWF0IjoxNzA1NDkzMTA0LCJqdGkiOiJ1cm46dXVpZDo1YTdlMjllMC0wNzdkLTRmZGQtYTFlMy1lN2QyYmVjNTBkYTYiLCJpc3MiOiJkaWQ6a2V5Ono2TWtwdWloWHFuNGo3ZG00cXBTMWVQOU1SMlNzZG9DRnVXaGRUWUY4ekdVdUhGWiIsIm5vbmNlIjoiMjAzOTQwMjkzNDAiLCJ2cCI6eyJAY29udGV4dCI6WyJodHRwczovL3d3dy53My5vcmcvMjAxOC9jcmVkZW50aWFscy92MSJdLCJ0eXBlIjpbIlZlcmlmaWFibGVQcmVzZW50YXRpb24iXSwiaWQiOiJ1cm46dXVpZDo1YTdlMjllMC0wNzdkLTRmZGQtYTFlMy1lN2QyYmVjNTBkYTYiLCJob2xkZXIiOiJkaWQ6a2V5Ono2TWtwdWloWHFuNGo3ZG00cXBTMWVQOU1SMlNzZG9DRnVXaGRUWUY4ekdVdUhGWiIsInZlcmlmaWFibGVDcmVkZW50aWFsIjpbImV5SmhiR2NpT2lKRlpFUlRRU0lzSW10cFpDSTZJbVJwWkRwclpYazZlalpOYTJWMVdIbDFXbU5JTVVNM2JtUkZjMFJyYVRGaVdqaFZOV2h4ZWxoaVlVUnViVFk1VlhWQ1kyOXBjbkJpSW4wLmV5SnBjM01pT2lKa2FXUTZhMlY1T25vMlRXdGxkVmg1ZFZwalNERkROMjVrUlhORWEya3hZbG80VlRWb2NYcFlZbUZFYm0wMk9WVjFRbU52YVhKd1lpSXNJbk4xWWlJNkltUnBaRHByWlhrNmVqWk5hM0IxYVdoWWNXNDBhamRrYlRSeGNGTXhaVkE1VFZJeVUzTmtiME5HZFZkb1pGUlpSamg2UjFWMVNFWmFJaXdpZG1NaU9uc2lRR052Ym5SbGVIUWlPbHNpYUhSMGNITTZMeTkzZDNjdWR6TXViM0puTHpJd01UZ3ZZM0psWkdWdWRHbGhiSE12ZGpFaUxDSm9kSFJ3Y3pvdkwzQjFjbXd1YVcxeloyeHZZbUZzTG05eVp5OXpjR1ZqTDI5aUwzWXpjREF2WTI5dWRHVjRkQzB6TGpBdU1pNXFjMjl1SWwwc0luUjVjR1VpT2xzaVZtVnlhV1pwWVdKc1pVTnlaV1JsYm5ScFlXd2lMQ0pQY0dWdVFtRmtaMlZEY21Wa1pXNTBhV0ZzSWwwc0ltTnlaV1JsYm5ScFlXeFRkV0pxWldOMElqcDdJblI1Y0dVaU9sc2lRV05vYVdWMlpXMWxiblJUZFdKcVpXTjBJbDBzSW1GamFHbGxkbVZ0Wlc1MElqcDdJbWxrSWpvaWRYSnVPblYxYVdRNllXTXlOVFJpWkRVdE9HWmhaQzAwWW1JeExUbGtNamt0Wldaa09UTTROVE0yT1RJMklpd2lkSGx3WlNJNld5SkJZMmhwWlhabGJXVnVkQ0pkTENKdVlXMWxJam9pU2taR0lIZ2dkbU10WldSMUlGQnNkV2RHWlhOMElETWdTVzUwWlhKdmNHVnlZV0pwYkdsMGVTSXNJbVJsYzJOeWFYQjBhVzl1SWpvaVZHaHBjeUIzWVd4c1pYUWdjM1Z3Y0c5eWRITWdkR2hsSUhWelpTQnZaaUJYTTBNZ1ZtVnlhV1pwWVdKc1pTQkRjbVZrWlc1MGFXRnNjeUJoYm1RZ2FHRnpJR1JsYlc5dWMzUnlZWFJsWkNCcGJuUmxjbTl3WlhKaFltbHNhWFI1SUdSMWNtbHVaeUIwYUdVZ2NISmxjMlZ1ZEdGMGFXOXVJSEpsY1hWbGMzUWdkMjl5YTJac2IzY2daSFZ5YVc1bklFcEdSaUI0SUZaRExVVkVWU0JRYkhWblJtVnpkQ0F6TGlJc0ltTnlhWFJsY21saElqcDdJblI1Y0dVaU9pSkRjbWwwWlhKcFlTSXNJbTVoY25KaGRHbDJaU0k2SWxkaGJHeGxkQ0J6YjJ4MWRHbHZibk1nY0hKdmRtbGtaWEp6SUdWaGNtNWxaQ0IwYUdseklHSmhaR2RsSUdKNUlHUmxiVzl1YzNSeVlYUnBibWNnYVc1MFpYSnZjR1Z5WVdKcGJHbDBlU0JrZFhKcGJtY2dkR2hsSUhCeVpYTmxiblJoZEdsdmJpQnlaWEYxWlhOMElIZHZjbXRtYkc5M0xpQlVhR2x6SUdsdVkyeDFaR1Z6SUhOMVkyTmxjM05tZFd4c2VTQnlaV05sYVhacGJtY2dZU0J3Y21WelpXNTBZWFJwYjI0Z2NtVnhkV1Z6ZEN3Z1lXeHNiM2RwYm1jZ2RHaGxJR2h2YkdSbGNpQjBieUJ6Wld4bFkzUWdZWFFnYkdWaGMzUWdkSGR2SUhSNWNHVnpJRzltSUhabGNtbG1hV0ZpYkdVZ1kzSmxaR1Z1ZEdsaGJITWdkRzhnWTNKbFlYUmxJR0VnZG1WeWFXWnBZV0pzWlNCd2NtVnpaVzUwWVhScGIyNHNJSEpsZEhWeWJtbHVaeUIwYUdVZ2NISmxjMlZ1ZEdGMGFXOXVJSFJ2SUhSb1pTQnlaWEYxWlhOMGIzSXNJR0Z1WkNCd1lYTnphVzVuSUhabGNtbG1hV05oZEdsdmJpQnZaaUIwYUdVZ2NISmxjMlZ1ZEdGMGFXOXVJR0Z1WkNCMGFHVWdhVzVqYkhWa1pXUWdZM0psWkdWdWRHbGhiSE11SW4wc0ltbHRZV2RsSWpwN0ltbGtJam9pYUhSMGNITTZMeTkzTTJNdFkyTm5MbWRwZEdoMVlpNXBieTkyWXkxbFpDOXdiSFZuWm1WemRDMHpMVEl3TWpNdmFXMWhaMlZ6TDBwR1JpMVdReTFGUkZVdFVFeFZSMFpGVTFRekxXSmhaR2RsTFdsdFlXZGxMbkJ1WnlJc0luUjVjR1VpT2lKSmJXRm5aU0o5ZlN3aWFXUWlPaUprYVdRNmEyVjVPbm8yVFd0elJtNWhlRFo0UTBKWFpHODJhR2htV2pkd1JYTmllV0Z4T1UxTlRtUnRRVUpUTVU1eVkwTkVXa3B5TXlKOUxDSnBaQ0k2SW5WeWJqcDFkV2xrT2pReE56ZGxNRFE0TFRsaE5HRXRORGMwWlMwNVpHTTJMV0ZsWkRSbE5qRmhOalF6T1NJc0ltbHpjM1ZsY2lJNkltUnBaRHByWlhrNmVqWk5hM05HYm1GNE5uaERRbGRrYnpab2FHWmFOM0JGYzJKNVlYRTVUVTFPWkcxQlFsTXhUbkpqUTBSYVNuSXpJaXdpYVhOemRXRnVZMlZFWVhSbElqb2lNakF5TkMwd01TMHhOMVF4TWpvd05Ub3dOQzR5TlRJMU16QmFJaXdpWlhod2FYSmhkR2x2YmtSaGRHVWlPaUl5TURJMExUQXhMVEU1VkRFeU9qQTFPakEwTGpJMU16QTNOVm9pTENKdVlXMWxJam9pU2taR0lIZ2dkbU10WldSMUlGQnNkV2RHWlhOMElETWdTVzUwWlhKdmNHVnlZV0pwYkdsMGVTSjlmUS4yLV9NaXc3RmpjdkpfUlBhYmVwS1VJeS01amZSajBoa2stTXRnUlNzMHlEaTFsZnlialE2cTh1Wks3cndPdEQyakc0ZC1mSzRSNmdMZTRheDMtU3JBQSJdfX0.rdLymfQCVHt-q-BQYvlGGiABkigkywdcIlPhVBCDJobpOmfhm-oOjmRQUi8NAFzZnRFlqGafHf59YqYIVbs2DA

Full Example

import id.walt.credentials.CredentialBuilder
import id.walt.credentials.CredentialBuilderType
import id.walt.credentials.PresentationBuilder
import id.walt.crypto.keys.KeyType
import id.walt.crypto.keys.LocalKey
import id.walt.crypto.utils.JsonUtils.toJsonObject
import kotlinx.serialization.json.JsonPrimitive
import kotlin.time.Duration.Companion.days
import id.walt.did.dids.DidService
import id.walt.sdjwt.DecoyMode
import id.walt.sdjwt.SDField
import id.walt.sdjwt.SDMap
import kotlin.js.ExperimentalJsExport

@OptIn(ExperimentalJsExport::class)
suspend fun main() {

    DidService.minimalInit()

    val myIssuerKey = LocalKey.generate(KeyType.Ed25519)
    val myIssuerDid = DidService.registerByKey("key", myIssuerKey).did

    val mySubjectKey = LocalKey.generate(KeyType.Ed25519)
    val mySubjectDid = DidService.registerByKey("key", mySubjectKey).did

    // Creating The Verifiable Credential
    val vc = CredentialBuilder(CredentialBuilderType.W3CV11CredentialBuilder).apply {
        addContext("https://purl.imsglobal.org/spec/ob/v3p0/context-3.0.2.json")

        addType("OpenBadgeCredential")
        credentialId = "urn:uuid:4177e048-9a4a-474e-9dc6-aed4e61a6439"

        issuerDid = "did:key:z6MksFnax6xCBWdo6hhfZ7pEsbyaq9MMNdmABS1NrcCDZJr3"

        validFromNow()
        validFor(2.days)

        subjectDid = "did:key:z6MksFnax6xCBWdo6hhfZ7pEsbyaq9MMNdmABS1NrcCDZJr3"

        useData("name", JsonPrimitive("JFF x vc-edu PlugFest 3 Interoperability"))

        useCredentialSubject(
                mapOf(
                        "type" to listOf("AchievementSubject"),
                        "achievement" to mapOf(
                                "id" to "urn:uuid:ac254bd5-8fad-4bb1-9d29-efd938536926",
                                "type" to listOf("Achievement"),
                                "name" to "JFF x vc-edu PlugFest 3 Interoperability",
                                "description" to "This wallet supports the use of W3C Verifiable Credentials and has demonstrated interoperability during the presentation request workflow during JFF x VC-EDU PlugFest 3.",
                                "criteria" to mapOf(
                                        "type" to "Criteria",
                                        "narrative" to "Wallet solutions providers earned this badge by demonstrating interoperability during the presentation request workflow. This includes successfully receiving a presentation request, allowing the holder to select at least two types of verifiable credentials to create a verifiable presentation, returning the presentation to the requestor, and passing verification of the presentation and the included credentials."
                                ),
                                "image" to mapOf(
                                        "id" to "https://w3c-ccg.github.io/vc-ed/plugfest-3-2023/images/JFF-VC-EDU-PLUGFEST3-badge-image.png",
                                        "type" to "Image"
                                )
                        )
                ).toJsonObject()
        )
    }.buildW3C()

    // Signing The Verifiable Credential
    val jwtVc: String = vc.signJws(myIssuerKey, myIssuerDid, mySubjectDid)

    // Creating Verifiable Presentation
    val vp = PresentationBuilder().apply {
        did = mySubjectDid

        nonce = "20394029340"

        addCredential(JsonPrimitive(jwtVc))
    }

    // Sign Verifiable Presentation as JWT
    val vpSigned = vp.buildAndSign(mySubjectKey)

    println(vpSigned)
}