Skip to content

kmandalas/spring-boot-vci-vp

Repository files navigation

Spring Boot SD-JWT, mDoc & VCI/VP Demo

Explore how SD-JWTs, mDoc (ISO 18013-5), OIDC4VCI, and OIDC4VP enable user-consented, selective disclosure of Verifiable Credentials using open standards in a demo setup. The project also implements wallet attestation (WIA/WUA), DPoP-bound tokens, and Token Status List revocation, following the HAIP (High Assurance Interoperability Profile) specification and EUDI Architecture Reference Framework.

Related articles:

OID4VCI Conformance

OpenID

The auth-server + issuer (acting as one OID4VCI Credential Issuer) and K-Wallet (Android) have successfully completed the OpenID Foundation Conformance Suite self-assessment for OID4VCI 1.0 Final:

Role Test Result
Issuer oid4vci-1_0-issuer-metadata-test PASSED
Issuer oid4vci-1_0-issuer-happy-flow PASSED
Issuer oid4vci-1_0-issuer-ensure-request-object-with-multiple-aud-succeeds PASSED
Wallet oid4vci-1_0-wallet-happy-path PASSED
Wallet oid4vci-1_0-wallet-happy-path-with-scopes PASSED
Wallet oid4vci-1_0-wallet-happy-path-with-scopes-without-authorization-details-in-token-response PASSED

Issuer profile (Feb 2026): client_attestation, dpop, wallet_initiated, simple, haip, unsigned, authorization_code

Wallet profile (Mar 2026): dpop, client_attestation, wallet_initiated, simple, haip, unsigned, authorization_code, by_value

Note: This is a self-assessment via the OpenID conformance suite β€” it validates protocol-level compliance (OID4VCI spec flows, token shapes, HAIP rules). It does not certify infrastructure security (HSMs, datacenter posture, LoA High hardware requirements, etc.).


Architecture

The system consists of six independent Spring Boot applications, built with Spring Boot 4.0.3, Java 25, and Spring Security 7. All modules support GraalVM Native Image compilation.

Module Port Description
auth-server 9000 OAuth2 Authorization Server with PAR, DPoP, and WIA-based client authentication
issuer 8080 Credential Issuer β€” validates WUA revocation via Token Status List, issues SD-JWT and mDoc credentials with revocation support (publishes own Token Status List)
verifier 9002 Credential Verifier β€” HAIP-compliant VP flow with JAR, DCQL, encrypted responses, and Token Status List revocation check
wallet-provider 9001 Issues Wallet Instance Attestations (WIA) and Wallet Unit Attestations (WUA), with support for both local and remote WSCD attestation
trust-validator 8090 X.509 trust chain validation service β€” decouples certificate trust evaluation from individual services (feature-flagged, see below)
qtsp-mock 9003 Mock QTSP β€” CSC API v2 (ETSI TS 119 432) for remote WSCD key management

VCI

Wallet-Initiated Issuance after Installation

The End-User installs a new Wallet and opens it. The Wallet offers the End-User a selection of Credentials that the End-User may obtain from a Credential Issuer, e.g. a national identity Credential, a mobile driving license, or a public transport ticket. The corresponding Credential Issuers (and their URLs) are pre-configured by the Wallet or follow some discovery processes that are out of scope for this specification. By clicking on one of these options corresponding to the Credentials available for issuance, the issuance process starts using a flow supported by the Credential Issuer (Pre-Authorized Code flow or Authorization Code flow).

Wallet Providers may also provide a marketplace where Issuers can register to be found for Wallet-initiated flows.

References:

sequenceDiagram
    participant User
    participant WalletApp
    participant IssuerAuthServer as Authorization Server
    participant Issuer
    participant AuthenticSource

    User->>WalletApp: Opens wallet app
    User->>WalletApp: Unlocks app with biometrics
    User->>WalletApp: Selects "Request VC" deep link
    WalletApp->>IssuerAuthServer: Redirect to login (Auth Code Flow)

    Note over User,IssuerAuthServer: Browser is opened for authentication and consent

    User->>IssuerAuthServer: Provides credentials and consent
    IssuerAuthServer-->>WalletApp: Redirect with auth code (via deep link)
    WalletApp->>WalletApp: Generate DPoP proof
    WalletApp->>IssuerAuthServer: Exchange code for access token (with DPoP)
    IssuerAuthServer-->>WalletApp: Respond with DPoP-bound access token
    WalletApp->>WalletApp: Prepare credential request with JWT proof
    WalletApp->>Issuer: Call credential endpoint with JWT proof + DPoP
    Issuer->>Issuer: Validate DPoP proof and JWT proof
    Issuer->>AuthenticSource: Retrieve user credentials
    AuthenticSource-->>Issuer: Return credentials
    Issuer->>Issuer: Allocate Token Status List index
    Issuer->>Issuer: Prepare SD-JWT or mDoc credential
    Issuer-->>WalletApp: Return credential (dc+sd-jwt or mso_mdoc format)
    WalletApp->>WalletApp: Verify SD-JWT signature using x5c certificate
    WalletApp->>WalletApp: Decode & Display verifiable credentials
    WalletApp->>WalletApp: Save credentials in Encrypted Shared Preferences

vci-auth-code-flow.png

Issuance Enhancements

The VCI flow incorporates several security mechanisms beyond the basic Authorization Code Flow:

  • PAR (Pushed Authorization Requests) β€” The wallet pushes authorization parameters to a dedicated endpoint before redirecting, preventing request tampering and reducing URL size (RFC 9126).
  • WIA + attest_jwt_client_auth β€” At the PAR and Token endpoints the wallet presents a Wallet Instance Attestation (WIA) JWT issued by the wallet-provider together with a Proof-of-Possession JWT, implementing attestation-based client authentication per draft-ietf-oauth-attestation-based-client-auth.
  • DPoP β€” Access tokens are sender-constrained via Demonstrating Proof-of-Possession (RFC 9449). The auth-server binds tokens to the wallet's DPoP key, and the issuer verifies the binding on each request.
  • WUA at credential endpoint β€” The wallet includes a Wallet Unit Attestation (WUA) in the key_attestation header of the JWT proof. The issuer validates the WUA signature, checks the attested WSCD type (TEE/StrongBox), and verifies WUA revocation status against the wallet-provider's Token Status List before issuing the credential.

SD-JWT

The credential is issued in dc+sd-jwt format with an x5c certificate chain in the header for signature verification.

Sample (demo):

eyJ4NWMiOlsiTUlJQmtUQ0NBVGVnQXdJQkFnSVVkeVljbDE5ZFlCSjhtY1hHc2NqVXN4c2k2RGt3Q2dZSUtvWkl6ajBFQXdJd0hqRWNNQm9HQTFVRUF3d1RkbU10YVhOemRXVnlMbVYxWkdsM0xtUmxkakFlRncweU5qQXhNREl5TVRVeE1UbGFGdzB5TnpBeE1ESXlNVFV4TVRsYU1CNHhIREFhQmdOVkJBTU1FM1pqTFdsemMzVmxjaTVsZFdScGR5NWtaWFl3V1RBVEJnY3Foa2pPUFFJQkJnZ3Foa2pPUFFNQkJ3TkNBQVJ3Y08waG9qaFNOYzdvT3BTRHpYWWF0SnBvLzJKOENPSWxPOVdHRlpmR1JZVEhNalVjZTlBT0VhczVEU0NZQmREZ284WFVsM29XYXU2UC9KdytmbmlYbzFNd1VUQWRCZ05WSFE0RUZnUVVUVm82S2xNYjZxMkZETFg1UXFPMUV4NkM3b0l3SHdZRFZSMGpCQmd3Rm9BVVRWbzZLbE1iNnEyRkRMWDVRcU8xRXg2QzdvSXdEd1lEVlIwVEFRSC9CQVV3QXdFQi96QUtCZ2dxaGtqT1BRUURBZ05JQURCRkFpRUE2SXJlSU5TV3VyZFFQbjFtNGZCWDJCU2dMa1R4V3ZLOVBRTHgxN0FPaWdZQ0lHZWJZNlkyNnliUEhObnhRMkVpOW1CTFMrK1QwVWN0MXJQVWczQjkzdlJtIl0sImtpZCI6Imlzc3Vlci1rZXktMSIsInR5cCI6ImRjK3NkLWp3dCIsImFsZyI6IkVTMjU2In0.eyJpc3MiOiJodHRwOi8vMTkyLjE2OC4xMDAuNDQvY3JlZGVudGlhbCIsIl9zZCI6WyI3N2RZam5IeDM3RXJvWFdiMEk0Q3hSdS1KNVJKZG9SZWZsVS1mTHNObzljIiwiZTFpOTNVbnNTenR1QzJ3X1AyZnFxdU95Q01QX1VXYWJCdU16T1plRnVXbyIsInFqbndxTm5sekZXRFNWY0NCTDZYMGlrNHkyQXd0T245cDVuRkJ6Z3RUU0EiXSwiY25mIjp7Imp3ayI6eyJrdHkiOiJFQyIsImNydiI6IlAtMjU2Iiwia2lkIjoid2FsbGV0LWtleSIsIngiOiJ5WEFjd05UN0dRZlhwQzJIVmdSRmJlckgycjdYMzl1YXd0VkNaU1hTQVVVIiwieSI6IlNTY1QyWER0dHRqVkVaakRWdkNwaV9DbVY5TEJINUlwYkZoZmpMYjdKaTQiLCJhbGciOiJFUzI1NiJ9fSwiY29tcGFueSI6IlVzZXJDb3JwIiwiaWF0IjoxNzY3Nzg2ODM2LCJ2Y3QiOiJ1cm46ZXUuZXVyb3BhLmVjLmV1ZGk6cGRhMToxIn0.8szE4ppARFl4fVOYWboVeZHBiS0YquxxVG2Hza_Lpw8w-yU-fLOTvPRK4HC4a1Yub2S8kASSsBiZuSXhgLkiRA

πŸ’‘ Paste it on https://www.sdjwt.co for inspection.

sdjwt.png

mDoc (mso_mdoc)

Credentials can also be issued in mso_mdoc format (ISO 18013-5). The mDoc credential is a CBOR-encoded structure containing the Mobile Security Object (MSO) with issuer-signed data elements and digest-based integrity protection. The response is base64url-encoded CBOR.


Demo wallet app (Android)

Available here along with instructions and screen recordings


VP

Same Device & Cross Device Flow

The verifier web UI is available at http://localhost:9002/verifier/select. Select a credential format (SD-JWT or mDoc) and click Request Presentation to generate a QR code and deep links. Two flows are supported:

  • Same-device: Tap the haip-vp:// or openid4vp:// deep link to open the wallet directly on the same device.
  • Cross-device: Scan the QR code with the wallet app on another device.

In both cases, the verifier signs the authorization request as a JAR (JWT with x5c header) and the wallet encrypts the VP response using ECDH-ES + A256GCM. The verifier UI polls for the result via HTMX and displays the disclosed claims inline once the wallet submits the VP.

verifier-ui.png

sequenceDiagram
    participant UA as User Agent
    participant W as Wallet
    participant V as Verifier
    participant IS as Issuer
    UA ->> V: Trigger presentation
    V ->> V: Generate ephemeral encryption key pair
    V ->> V: Create authorization request with DCQL query
    V ->> V: Sign request as JAR (JWT with x5c header)
    V -->> UA: Render request as QR/deep link (haip-vp://)
    UA ->> W: Trigger wallet and pass request
    W ->> V: GET request_uri (Accept: application/oauth-authz-req+jwt)
    V -->> W: Signed JAR
    W ->> W: Verify JAR signature using x5c certificate
    W ->> W: Validate x509_hash matches client_id
    W ->> W: Parse DCQL query from verified JWT
    W ->> W: Fetch locally stored VC
    W ->> W: Prompt user for selective disclosure
    alt dc+sd-jwt
        W ->> W: Create VP with selected disclosures + Key Binding JWT
    else mso_mdoc
        W ->> W: Build DeviceResponse with SessionTranscript & DeviceAuth (COSE_Sign1)
    end
    W ->> W: Encrypt response (ECDH-ES + A256GCM)
    W ->> V: POST encrypted vp_token (direct_post.jwt)
    V ->> V: Decrypt response with ephemeral private key
    alt dc+sd-jwt
        V ->> IS: Fetch issuer's public key (or use x5c from credential)
        V ->> V: Verify SD-JWT credential signature
        V ->> V: Verify Key Binding JWT
    else mso_mdoc
        V ->> V: Verify IssuerAuth (COSE_Sign1) + MSO digests
        V ->> V: Verify SessionTranscript
        V ->> V: Verify DeviceAuth signature
    end
    V ->> IS: Check Token Status List (revocation)
    V -->> W: Return verification result
    W ->> W: Display verification outcome

vp-same-device-flow.png

DCQL Query

The verifier uses DCQL (Digital Credentials Query Language) to request specific claims from credentials.

SD-JWT sample (demo):

{
  "client_id": "x509_hash:a54_NCUlnbgC-1PfaZIppUTinKy4ITcmSo6KtXxyFCE",
  "response_type": "vp_token",
  "response_mode": "direct_post.jwt",
  "response_uri": "https://verifier.example.com/verify-vp/{requestId}",
  "nonce": "e2c1d8f1-ffc1-4412-871d-94a4bc14a6b5",
  "dcql_query": {
    "credentials": [
      {
        "id": "pda1_credential",
        "format": "dc+sd-jwt",
        "meta": {
          "vct_values": ["urn:eu.europa.ec.eudi:pda1:1"]
        },
        "claims": [
          { "path": ["credential_holder"] },
          { "path": ["nationality"] },
          { "path": ["competent_institution"] }
        ]
      }
    ]
  },
  "client_metadata": {
    "client_name": "Demo Verifier Inc.",
    "logo_uri": "https://example.com/logo.png",
    "purpose": "Verify your Portable Document A1 credentials",
    "jwks": {
      "keys": [{ "kty": "EC", "crv": "P-256", "...": "ephemeral encryption key" }]
    },
    "authorization_encrypted_response_alg": "ECDH-ES",
    "authorization_encrypted_response_enc": "A256GCM"
  }
}

For mDoc credentials, the DCQL query uses mso_mdoc format with a doctype_value and two-element claim paths [namespace, elementIdentifier]:

{
  "dcql_query": {
    "credentials": [
      {
        "id": "pda1_credential",
        "format": "mso_mdoc",
        "meta": {
          "doctype_value": "eu.europa.ec.eudi.pda1.1"
        },
        "claims": [
          { "path": ["eu.europa.ec.eudi.pda1.1", "credential_holder"] },
          { "path": ["eu.europa.ec.eudi.pda1.1", "nationality"] },
          { "path": ["eu.europa.ec.eudi.pda1.1", "competent_institution"] }
        ]
      }
    ]
  }
}

vp_token Response

The wallet sends an encrypted JWE containing the vp_token in DCQL format:

{
  "vp_token": {
    "pda1_credential": ["<SD-JWT with disclosures and KB-JWT>"]
  },
  "state": "optional-state-value"
}

For mDoc credentials, the vp_token value is a base64url-encoded CBOR DeviceResponse containing DeviceAuth (COSE_Sign1 with session transcript) and the disclosed data elements.

Sample vp_token (demo):

eyJ4NWMiOlsiTUlJQmtUQ0NBVGVnQXdJQkFnSVVkeVljbDE5ZFlCSjhtY1hHc2NqVXN4c2k2RGt3Q2dZSUtvWkl6ajBFQXdJd0hqRWNNQm9HQTFVRUF3d1RkbU10YVhOemRXVnlMbVYxWkdsM0xtUmxkakFlRncweU5qQXhNREl5TVRVeE1UbGFGdzB5TnpBeE1ESXlNVFV4TVRsYU1CNHhIREFhQmdOVkJBTU1FM1pqTFdsemMzVmxjaTVsZFdScGR5NWtaWFl3V1RBVEJnY3Foa2pPUFFJQkJnZ3Foa2pPUFFNQkJ3TkNBQVJ3Y08waG9qaFNOYzdvT3BTRHpYWWF0SnBvLzJKOENPSWxPOVdHRlpmR1JZVEhNalVjZTlBT0VhczVEU0NZQmREZ284WFVsM29XYXU2UC9KdytmbmlYbzFNd1VUQWRCZ05WSFE0RUZnUVVUVm82S2xNYjZxMkZETFg1UXFPMUV4NkM3b0l3SHdZRFZSMGpCQmd3Rm9BVVRWbzZLbE1iNnEyRkRMWDVRcU8xRXg2QzdvSXdEd1lEVlIwVEFRSC9CQVV3QXdFQi96QUtCZ2dxaGtqT1BRUURBZ05JQURCRkFpRUE2SXJlSU5TV3VyZFFQbjFtNGZCWDJCU2dMa1R4V3ZLOVBRTHgxN0FPaWdZQ0lHZWJZNlkyNnliUEhObnhRMkVpOW1CTFMrK1QwVWN0MXJQVWczQjkzdlJtIl0sImtpZCI6Imlzc3Vlci1rZXktMSIsInR5cCI6ImRjK3NkLWp3dCIsImFsZyI6IkVTMjU2In0.eyJpc3MiOiJodHRwOi8vMTkyLjE2OC4xMDAuNDQvY3JlZGVudGlhbCIsIl9zZCI6WyJIYlpUZ0Qyb1dTXzFlbUo2SW1FVi1aV0FULWN0dGw0bncyaFVJcDJiTXdjIiwiU2pSZXpkRU9xcE1kTVRval82NnpDbjVoMFVibHNlb3ZzeWNQX3BtSFZRcyIsInhmVzFKQU1CdjE4dTJabjA0S3N3V0RMUXJ3RW9ZWkJnekUzcmk0Qk54UkUiXSwiY25mIjp7Imp3ayI6eyJrdHkiOiJFQyIsImNydiI6IlAtMjU2Iiwia2lkIjoid2FsbGV0LWtleSIsIngiOiJPdy1qcGItc1VMRlQtcGxnR3RxSm9lVUUtVWhBTWNKYVVqa0N1VVJkeHVVIiwieSI6IndxYzhXeWZ1T3RRN0hqSnJvV3VfXzZVZGo4Z3J0V0pBN2t6WEZkSjZxaWciLCJhbGciOiJFUzI1NiJ9fSwiY29tcGFueSI6IlVzZXJDb3JwIiwiaWF0IjoxNzY3ODc1NjY1LCJ2Y3QiOiJ1cm46ZXUuZXVyb3BhLmVjLmV1ZGk6cGRhMToxIn0.Zu5Q9QOh3mxf-7TSA_rtlflh64bLThwsp8JTRWRdgEwmwKsycliE7A47nfGTdbhO-fcJ-12kiqP6U9u2niq8iA

πŸ’‘ Paste it on https://www.sdjwt.co for inspection.

vptoken.png

QR code and Deep Link

The verifier generates deep links using the haip-vp:// scheme (HAIP compliant) or openid4vp://:

haip-vp://?client_id=x509_hash%3Aa54_NCUlnbgC-1PfaZIppUTinKy4ITcmSo6KtXxyFCE&request_uri=https%3A%2F%2Fverifier.example.com%2Frequest-object%2F{requestId}

Wallet Provider

The wallet-provider module acts as the trust anchor for wallet instances and their hardware-backed keys.

WIA (Wallet Instance Attestation) β€” Issues oauth-client-attestation+jwt tokens that attest the wallet app's integrity and bind it to an ephemeral public key. The auth-server validates WIA at the PAR and Token endpoints to authenticate wallet clients without shared secrets.

WUA (Wallet Unit Attestation) β€” Issues key-attestation+jwt tokens after validating Android Key Attestation certificate chains against Google's root CA. The WUA captures the key's security level (software, TEE, or StrongBox) and maps it to ISO 18045 attack-potential resistance levels. The issuer checks the WUA before issuing credentials.

Remote WSCD (QTSP) β€” The wallet-provider also supports remote WSCD attestation via QtspAttestationService. When a wallet uses a remote signing key managed by a QTSP (see qtsp-mock), the wallet-provider validates the QTSP certificate chain against the trust-validator, verifies SCAL=2 compliance, and issues a WUA with wscd_type: "remote_qscd".

Token Status List β€” Each WUA is assigned an index in a compressed bitstring published as a signed JWT (application/statuslist+jwt) per draft-ietf-oauth-status-list. The issuer fetches the status list and checks the relevant bit to determine whether a WUA has been revoked, providing a privacy-preserving revocation mechanism.


Trust Validator

The trust-validator is a standalone X.509 trust chain validation service that answers: "is this certificate chain trusted for this verification context?"

It decouples trust evaluation from individual services β€” the auth-server, issuer, and verifier each delegate chain validation via a simple POST /trust call instead of embedding their own trust logic. This means the trust infrastructure can be upgraded (e.g. to EU Lists of Trusted Lists) without touching service code.

Feature-flagged in all consumers. Each consumer (auth-server, issuer, verifier, wallet-provider) has a trust-validator.enabled flag that defaults to false. When disabled, consumers fall back to their configured trusted-issuers lists.

Key capabilities:

  • 15 EUDI ARF verification contexts β€” WalletInstanceAttestation, PID, QEAA, PubEAA, EAA, and their status-list counterparts, plus WalletRelyingPartyAccessCertificate, QTSPSigningCertificate, and Custom
  • Two trust source modes β€” local KeyStore (ships with project CA, works out of the box) or EU LoTL via DSS with scheduled refresh
  • Browser UI at http://localhost:8090/validate for manual certificate chain testing
  • Consumer integration β€” identical TrustValidatorClient in auth-server (WIA chain), issuer (WUA chain), and verifier (credential issuer chain)

In a production deployment, this service would sit on an internal network β€” its security posture (mTLS, service mesh, network isolation) depends on the zero-trust model of the environment.


QTSP Mock (Remote WSCD)

The qtsp-mock module provides a mock Qualified Trust Service Provider implementing the CSC API v2 (ETSI TS 119 432) for remote WSCD key management. It demonstrates how a wallet can use remotely-managed signing keys instead of device-local keys (Android Keystore).

CSC API endpoints:

  • POST /csc/v2/credentials/list β€” List available signing credentials
  • POST /csc/v2/credentials/info β€” Get credential details (key algorithm, certificate chain, SCAL level)
  • POST /csc/v2/credentials/authorize β€” Obtain a single-use SAD (Signature Activation Data) token
  • POST /csc/v2/signatures/signHash β€” Sign a hash using the authorized credential

Key features:

  • EC P-256 signing key generated on startup with a stable CA (ships with project)
  • Single-use SAD tokens for signature activation (SCAL=2)
  • Static API key authentication (ApiKey header)
  • Dashboard UI at /dashboard (Thymeleaf + HTMX) for testing CSC operations interactively

Integration with the ecosystem:

  • wallet-provider β€” QtspAttestationService accepts qtsp_attestation type requests, validates the QTSP certificate chain against the trust-validator, verifies SCAL=2, and issues a WUA with wscd_type: "remote_qscd"
  • trust-validator β€” QTSP CA is included in local-trust.jks; chain validation uses the QTSPSigningCertificate verification context
  • K-Wallet Android app β€” Supports toggling between local (Android Keystore) and remote (QTSP) signing modes

In production, the mock QTSP would be replaced by a certified QTSP's HSM-backed infrastructure. See qtsp-mock/notes/QTSP-REMOTE-QSCD.md for full details, diagrams, and spec compliance notes.


HAIP Features

This implementation includes the following HAIP-compliant features:

Feature Description
PAR Pushed Authorization Requests (RFC 9126)
WIA Wallet Instance Attestation with attest_jwt_client_auth (draft-ietf-oauth-attestation-based-client-auth)
WUA Wallet Unit Attestation for hardware key security with Token Status List revocation
DPoP Demonstrating Proof of Possession for access tokens (RFC 9449)
JAR with x5c JWT-Secured Authorization Requests signed with X.509 certificate
x509_hash client_id Client identification via SHA-256 hash of DER-encoded certificate
DCQL Digital Credentials Query Language for credential requests
dc+sd-jwt HAIP-compliant credential format with x5c header
mso_mdoc ISO 18013-5 mDoc credential format with COSE_Sign1 IssuerAuth
VP Encryption Response encryption using ECDH-ES + A256GCM
haip-vp:// scheme HAIP-compliant URI scheme for wallet invocation
⭐ Remote WSCD CSC API v2 (ETSI TS 119 432) for remote WSCD key management via QTSP

⚠️ Disclaimer

This repo contains an experimental project created for learning and demonstration purposes. The implementation is not intended for production use.


πŸ’Ό Enterprise & Professional Services

This project is a teaser β€” a working proof-of-concept demonstrating a fully functional EUDI-compliant ecosystem. If you need a production-ready solution, I can deliver a complete, end-to-end EUDI stack tailored to your needs:

What can be delivered

Full-stack engagements

  • HSM integration β€” Hardware Security Module support for issuer and wallet-provider signing keys (LoA High compliance)
  • Remote WSCA β€” Production-grade Remote Wallet Secure Cryptographic Application with certified QTSP HSM integration (the included qtsp-mock demonstrates the CSC API v2 flow end-to-end)
  • Production-grade storage β€” Replace H2 with a production database of your choice (PostgreSQL, MySQL, CosmosDB, etc.); credential status, WUA, and session data on a robust, scalable store
  • Key Vault integration β€” AWS KMS, Azure Key Vault, or HashiCorp Vault for secret/key lifecycle management
  • Full microservices setup β€” Containerised (Docker/Kubernetes), horizontally scalable, with distributed caching (e.g. Redis) for JTI replay protection, session management etc.
  • Wallet apps (Android & iOS) β€” Custom-branded and themed to your organisation's identity; delivered as your own product
  • Complete EUDI solution β€” Issuer + Verifier + Wallet App (Android & iOS) + Wallet Provider as a coherent, deployable product
  • Admin consoles β€” Management UIs for wallet provider, issuer, and verifier operations (credential revocation, status list monitoring, WUA management, audit logs)
  • Multiple credential types β€” Extend beyond the demo PDA1 to PID, mDL, EAA, and custom attestation types per your rulebooks
  • LoTL / Trust Validator β€” ETSI TS 119 612 Lists of Trusted Lists integration for federated, EU-compliant trust infrastructure across issuers, verifiers, and wallet providers
  • LoA High compliance β€” Architecture and attestation chain designed to satisfy Level of Assurance High requirements under eIDAS 2.0 / ARF

Standalone / component engagements

  • Standalone Verifier for Relying Parties β€” If your use case is accepting EUDI wallet presentations β€” without issuing credentials or operating a wallet β€” I can consult on and implement a standalone, HAIP-compliant OID4VP verifier tailored to your credential types, trust model, and integration requirements; from architecture advice through to production implementation
  • Standalone Issuer β€” If you need to issue verifiable credentials (e.g. as a government agency, university, or bank) without operating a full EUDI stack, I can design and implement an OID4VCI-compliant issuer for your specific credential types and rulebooks, including integration with your Authentic Sources (civil registries, population registers, HR systems, or any internal database)

Contact

Interested? Reach out via GitHub to discuss your requirements.


License

Business Source License 1.1 β€” free for non-production use.

About

A demonstration of issuing and presenting Verifiable Credentials in SD-JWT & mDoc format using Spring Boot microservices as backend and a Kotlin Android app (wallet) client-side

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors