Protocol Abstraction Layer
Overview
The protocol abstraction layer provides a unified interface for credential exchange operations across different protocols (DIDComm, OIDC4VCI, CHAPI, OIDC4VP, etc.). This allows applications to use any protocol interchangeably without being tightly coupled to a specific implementation.
Architecture
High-Level Architecture
graph TB
App[Application Code]
Registry[CredentialExchangeProtocolRegistry]
Protocol[CredentialExchangeProtocol Interface]
DIDComm[DIDComm Protocol]
OIDC4VCI[OIDC4VCI Protocol]
CHAPI[CHAPI Protocol]
App --> Registry
Registry --> Protocol
Protocol --> DIDComm
Protocol --> OIDC4VCI
Protocol --> CHAPI
style Registry fill:#e1f5ff
style Protocol fill:#fff4e1
style DIDComm fill:#e8f5e9
style OIDC4VCI fill:#e8f5e9
style CHAPI fill:#e8f5e9
Component Diagram
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
┌─────────────────────────────────────────────────────────┐
│ CredentialExchangeProtocolRegistry │
│ (Manages multiple protocol implementations) │
└─────────────────────────────────────────────────────────┘
│
│ uses
▼
┌─────────────────────────────────────────────────────────┐
│ CredentialExchangeProtocol │
│ (Common interface for all protocols) │
└─────────────────────────────────────────────────────────┘
│
┌───────────────┼───────────────┐
│ │ │
▼ ▼ ▼
┌──────────────┐ ┌──────────────┐ ┌──────────────┐
│ DIDComm │ │ OIDC4VCI │ │ CHAPI │
│ Protocol │ │ Protocol │ │ Protocol │
└──────────────┘ └──────────────┘ └──────────────┘
Core Components
1. CredentialExchangeProtocol Interface
The main interface that all protocols implement:
1
2
3
4
5
6
7
8
9
10
interface CredentialExchangeProtocol {
val protocolName: String
val supportedOperations: Set<ExchangeOperation>
suspend fun offerCredential(request: CredentialOfferRequest): CredentialOfferResponse
suspend fun requestCredential(request: CredentialRequestRequest): CredentialRequestResponse
suspend fun issueCredential(request: CredentialIssueRequest): CredentialIssueResponse
suspend fun requestProof(request: ProofRequestRequest): ProofRequestResponse
suspend fun presentProof(request: ProofPresentationRequest): ProofPresentationResponse
}
2. Exchange Models
Common data models used across all protocols:
CredentialOfferRequest/CredentialOfferResponseCredentialRequestRequest/CredentialRequestResponseCredentialIssueRequest/CredentialIssueResponseProofRequestRequest/ProofRequestResponseProofPresentationRequest/ProofPresentationResponse
3. CredentialExchangeProtocolRegistry
Manages protocol registration and provides a unified API:
1
2
3
4
5
6
7
8
val registry = CredentialExchangeProtocolRegistry()
// Register protocols
registry.register(DidCommExchangeProtocol(didCommService))
registry.register(Oidc4VciExchangeProtocol(oidc4vciService))
// Use any protocol
val offer = registry.offerCredential("didcomm", request)
Supported Protocols
DIDComm V2
- Protocol Name:
"didcomm" - Supported Operations: All (offer, request, issue, proof request, proof presentation)
- Implementation:
DidCommExchangeProtocol - Status: ✅ Fully Implemented
- Library: Custom implementation with
didcomm-javaintegration - Documentation: DIDComm Protocol
OIDC4VCI
- Protocol Name:
"oidc4vci" - Supported Operations: Issuance only (offer, request, issue)
- Implementation:
Oidc4VciExchangeProtocol - Status: ✅ Implemented (Basic)
- Library: walt.id
waltid-openid4vc(optional) - Documentation: OIDC4VCI Protocol
CHAPI
- Protocol Name:
"chapi" - Supported Operations: Offer, issue, proof request, proof presentation
- Implementation:
ChapiExchangeProtocol - Status: ✅ Implemented (Basic)
- Library: Custom implementation (browser API wrapper)
- Documentation: CHAPI Protocol
Message Flow
Credential Issuance Flow
sequenceDiagram
participant Issuer
participant Registry
participant Protocol
participant Holder
Issuer->>Registry: offerCredential("didcomm", request)
Registry->>Protocol: offerCredential(request)
Protocol->>Protocol: Create DIDComm message
Protocol->>Protocol: Encrypt & Sign
Protocol-->>Registry: CredentialOfferResponse
Registry-->>Issuer: Offer created (offerId)
Holder->>Registry: requestCredential("didcomm", request)
Registry->>Protocol: requestCredential(request)
Protocol->>Protocol: Create request message
Protocol-->>Registry: CredentialRequestResponse
Registry-->>Holder: Request created (requestId)
Issuer->>Registry: issueCredential("didcomm", request)
Registry->>Protocol: issueCredential(request)
Protocol->>Protocol: Create credential message
Protocol->>Protocol: Sign credential
Protocol-->>Registry: CredentialIssueResponse
Registry-->>Issuer: Credential issued
Proof Request Flow
sequenceDiagram
participant Verifier
participant Registry
participant Protocol
participant Prover
Verifier->>Registry: requestProof("didcomm", request)
Registry->>Protocol: requestProof(request)
Protocol->>Protocol: Create proof request
Protocol-->>Registry: ProofRequestResponse
Registry-->>Verifier: Request created (requestId)
Prover->>Registry: presentProof("didcomm", request)
Registry->>Protocol: presentProof(request)
Protocol->>Protocol: Create presentation
Protocol->>Protocol: Sign presentation
Protocol-->>Registry: ProofPresentationResponse
Registry-->>Prover: Proof presented
Usage Examples
Basic Usage
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
// Create registry
val registry = CredentialExchangeProtocolRegistry()
// Register DIDComm
val didCommService = DidCommFactory.createInMemoryService(kms, resolveDid)
registry.register(DidCommExchangeProtocol(didCommService))
// Offer credential
val offer = registry.offerCredential(
protocolName = "didcomm",
request = CredentialOfferRequest(
issuerDid = "did:key:issuer",
holderDid = "did:key:holder",
credentialPreview = CredentialPreview(
attributes = listOf(
CredentialAttribute("name", "Alice"),
CredentialAttribute("email", "alice@example.com")
)
),
options = mapOf(
"fromKeyId" to "did:key:issuer#key-1",
"toKeyId" to "did:key:holder#key-1"
)
)
)
Complete Exchange Flow
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
// 1. Offer
val offer = registry.offerCredential("didcomm", offerRequest)
// 2. Request
val request = registry.requestCredential("didcomm", CredentialRequestRequest(
holderDid = holderDid,
issuerDid = issuerDid,
offerId = offer.offerId,
options = keyOptions
))
// 3. Issue
val issue = registry.issueCredential("didcomm", CredentialIssueRequest(
issuerDid = issuerDid,
holderDid = holderDid,
credential = credential,
requestId = request.requestId,
options = keyOptions
))
Protocol Switching
1
2
3
// Same API, different protocols
val didCommOffer = registry.offerCredential("didcomm", request)
val oidc4vciOffer = registry.offerCredential("oidc4vci", request)
SPI (Service Provider Interface)
Protocols can be auto-discovered using Java ServiceLoader:
- Implement
CredentialExchangeProtocolProvider - Create
META-INF/services/com.trustweave.credential.exchange.spi.CredentialExchangeProtocolProvider - List your provider class in the file
Example (DIDComm):
1
com.trustweave.credential.didcomm.exchange.spi.DidCommExchangeProtocolProvider
Protocol-Specific Options
Each protocol may require protocol-specific options in the options map:
DIDComm
fromKeyId: Sender’s key ID (required)toKeyId: Recipient’s key ID (required)encrypt: Whether to encrypt (default: true)thid: Thread ID (optional)
OIDC4VCI
credentialIssuer: OIDC credential issuer URL (required)
CHAPI
- Browser-specific options (to be defined)
Benefits
- Protocol Agnostic: Applications don’t need to know which protocol is being used
- Easy Switching: Change protocols by changing the protocol name
- Consistent API: Same operations across all protocols
- Extensible: Easy to add new protocols
- Type Safe: Strong typing for all operations
Protocol Implementation
For detailed information on implementing new protocols, see:
Future Enhancements
- Auto-discovery via SPI
- Protocol capability negotiation
- Protocol fallback/retry
- Protocol-specific validation
- Metrics and observability per protocol
- OIDC4VP implementation
- SIOPv2 implementation
- WACI implementation