OpenID Connect for Verifiable Credential Issuance (OIDC4VCI) implementation for TrustWeave.
Overview
OIDC4VCI is a protocol that enables credential issuance using OpenID Connect flows. It provides a standardized way for issuers to offer credentials and for holders to request and receive them.
importorg.trustweave.credential.oidc4vci.Oidc4VciServiceimportorg.trustweave.credential.oidc4vci.exchange.Oidc4VciExchangeProtocolimportorg.trustweave.credential.exchange.*importokhttp3.OkHttpClientimportorg.trustweave.credential.exchange.registry.ExchangeProtocolRegistriesimportorg.trustweave.credential.exchange.ExchangeServicesvalkms=// Your KMS instancevalhttpClient=OkHttpClient()valoidc4vciService=Oidc4VciService(credentialIssuerUrl="https://issuer.example.com",kms=kms,httpClient=httpClient)valprotocol=Oidc4VciExchangeProtocol(oidc4vciService)valregistry=ExchangeProtocolRegistries.default()registry.register(protocol)valexchangeService=ExchangeServices.createExchangeService(protocolRegistry=registry,credentialService=credentialService,didResolver=didResolver)
importorg.trustweave.credential.exchange.*importorg.trustweave.credential.exchange.request.ExchangeRequestimportorg.trustweave.credential.exchange.result.ExchangeResultimportorg.trustweave.credential.exchange.options.ExchangeOptionsimportorg.trustweave.credential.identifiers.*importorg.trustweave.did.identifiers.Didimportkotlinx.serialization.json.JsonPrimitivevalofferResult=exchangeService.offer(ExchangeRequest.Offer(protocolName="oidc4vci".requireExchangeProtocolName(),issuerDid=Did("did:key:issuer"),holderDid=Did("did:key:holder"),credentialPreview=CredentialPreview(attributes=listOf(CredentialAttribute("name","Alice"),CredentialAttribute("email","alice@example.com"))),options=ExchangeOptions.builder().addMetadata("credentialIssuer","https://issuer.example.com").addMetadata("credentialTypes",JsonPrimitive("VerifiableCredential,PersonCredential")).addMetadata("grants",JsonPrimitive("authorization_code")).addMetadata("issuer_state",JsonPrimitive("state123")).build()))valoffer=when(offerResult){isExchangeResult.Success->offerResult.valueelse->throwIllegalStateException("Offer failed: $offerResult")}// The offer's protocol-agnostic envelope holds the OIDC4VCI offer JSONvalmessageData=offer.messageEnvelope.messageData// JsonElement// The plugin serializes Oidc4VciOffer here; parse out e.g. offerUri:// Format: openid-credential-offer://?credential_issuer=...
importorg.trustweave.credential.model.vc.VerifiableCredentialimportorg.trustweave.credential.model.vc.CredentialSubjectimportorg.trustweave.credential.model.vc.Issuerimportorg.trustweave.credential.model.CredentialTypeimportorg.trustweave.core.identifiers.Iriimportkotlinx.serialization.json.JsonPrimitiveimportkotlinx.datetime.Clockvalcredential=VerifiableCredential(type=listOf(CredentialType.fromString("VerifiableCredential"),CredentialType.fromString("PersonCredential")),issuer=Issuer.IriIssuer(Iri("did:key:issuer")),issuanceDate=Clock.System.now(),credentialSubject=CredentialSubject(id=Iri("did:key:holder"),// CredentialSubject.id is Iri, not Didclaims=mapOf("name"toJsonPrimitive("Alice"),"email"toJsonPrimitive("alice@example.com"))))valissueResult=exchangeService.issue(ExchangeRequest.Issue(protocolName="oidc4vci".requireExchangeProtocolName(),issuerDid=Did("did:key:issuer"),holderDid=Did("did:key:holder"),credential=credential,requestId=credentialRequest.requestId,options=ExchangeOptions.builder().build()))valissue=when(issueResult){isExchangeResult.Success->issueResult.valueelse->throwIllegalStateException("Issue failed: $issueResult")}
OIDC4VCI Flow
Credential Offer: Issuer creates an offer URI or object
Authorization: Holder authorizes the request (if using authorization code flow)
Token Exchange: Holder exchanges authorization code for access token
Credential Request: Holder requests credential with proof of possession
Credential Issuance: Issuer issues credential via credential endpoint
Protocol-Specific Options
Credential Offer Options
credentialIssuer (required): URL of the credential issuer
credentialTypes: List of credential types to offer
grants: Grant types (e.g., authorization_code)
Credential Request Options
redirectUri: Redirect URI for authorization code flow
Credential Issuer Metadata
The service can fetch credential issuer metadata from /.well-known/openid-credential-issuer: