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:
- Verifiable Credentials with Spring Boot & Android
- Securing Verifiable Credentials with DPoP
- HAIP 1.0: Securing Verifiable Presentations
- More articles covering WIA, WUA, and Token Status List coming soon.
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.).
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 |
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:
- https://openid.net/specs/openid-4-verifiable-credential-issuance-1_0.html#section-3.3.3
- https://openid.net/specs/openid-4-verifiable-credential-issuance-1_0.html#name-wallet-initiated-issuance-a
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
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 perdraft-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_attestationheader 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.
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.
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.
Available here along with instructions and screen recordings
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://oropenid4vp://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.
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
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"] }
]
}
]
}
}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.
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}
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.
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, plusWalletRelyingPartyAccessCertificate,QTSPSigningCertificate, andCustom - 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/validatefor manual certificate chain testing - Consumer integration β identical
TrustValidatorClientin 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.
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 credentialsPOST /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) tokenPOST /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 (
ApiKeyheader) - Dashboard UI at
/dashboard(Thymeleaf + HTMX) for testing CSC operations interactively
Integration with the ecosystem:
- wallet-provider β
QtspAttestationServiceacceptsqtsp_attestationtype requests, validates the QTSP certificate chain against the trust-validator, verifies SCAL=2, and issues a WUA withwscd_type: "remote_qscd" - trust-validator β QTSP CA is included in
local-trust.jks; chain validation uses theQTSPSigningCertificateverification 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.
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.
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:
- 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 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)
Interested? Reach out via GitHub to discuss your requirements.
Business Source License 1.1 β free for non-production use.





