Credimi Fake VCI Capture Issuer
Credimi Fake VCI Capture Issuer is a local fake OpenID4VCI issuer for Credimi conformance work. It is not a production issuer.
Its purpose is to drive an external Wallet through an authorization-code issuance flow and capture the Wallet protocol values needed by OpenID Foundation VCI Wallet tests.
What It Captures
- Wallet OAuth
client_id - Wallet
redirect_uri - Wallet holder-binding public key as JWKS from credential proof JWT headers
- DPoP public JWK when present
- structured flow events for debugging and evidence
The implementation exposes compatibility endpoints directly and keeps the credential response minimal so the Wallet reaches /credential. At the end of the flow it uses Credo-TS to issue a holder-bound EEA SD-JWT VC with demo PID claims and Credimi branding.
Quick Start
Install dependencies:
pnpm install
Create local environment settings:
cp env.example .env
Initialize issuer state:
pnpm fake-issuer init \
--issuer-base-url https://issuer.example.test \
--data-dir ./data \
--credential-configuration-id urn:eu.europa.ec.eudi:pid:1
Start the issuer:
pnpm dev
Default local issuer URL is http://localhost:8080.
GUI
The browser GUI is enabled by default.
Open:
http://localhost:8080/
From the launcher, click New fake-issuance session to open a QR session in a new tab. Scan the QR with an EUDI Wallet. The session page updates as Wallet metadata, proof keys, DPoP keys, checks, and flow events are observed.
The GUI includes a Help button that opens the rendered project README in a new tab:
http://localhost:8080/ui/help
Disable the GUI by setting GUI_ENABLED=false in .env:
GUI_ENABLED=false
When disabled, /, /ui/help, and /ui/sessions/* are unavailable. API endpoints remain available.
API Capture Flow
Create a session:
curl -X POST http://localhost:8080/sessions
Choose a specific credential configuration for the offer:
curl -X POST http://localhost:8080/sessions \
-H 'Content-Type: application/json' \
-d '{"credential_configuration_id":"urn:eu.europa.ec.eudi:pid:1.attestation"}'
The issuer metadata exposes matching proof-specific scopes:
urn:eu.europa.ec.eudi:pid:1.jwturn:eu.europa.ec.eudi:pid:1.attestation
Get a Wallet deeplink:
curl http://localhost:8080/sessions/{sessionId}/deeplink
Retrieve the captured Wallet JWKS:
curl http://localhost:8080/sessions/{sessionId}/jwks
Retrieve the full normalized capture object:
curl http://localhost:8080/sessions/{sessionId}
Retrieve event evidence:
curl http://localhost:8080/sessions/{sessionId}/events
Conformance Values
Pass these captured values into the OIDF VCI Wallet conformance test:
- JWKS:
GET /sessions/{sessionId}/jwks client_id:observed.client_id.valuefromGET /sessions/{sessionId}redirect_uri:observed.redirect_uri.valuefromGET /sessions/{sessionId}
Configuration
Runtime configuration comes from generated issuer config and environment variables.
Issuer Config
pnpm fake-issuer init is idempotent and writes generated issuer keys/config below ./data, which is ignored by Git. Use --force to replace existing generated state.
Environment
.env is loaded automatically when present and is ignored by Git. Use env.example as the template.
Supported environment variables:
GUI_ENABLED: enables or disables browser GUI routes. Defaults totrue.PORT: overrides the configured listen port.
Example:
PORT=3000 pnpm dev
Troubleshooting
If /sessions/{sessionId}/jwks returns wallet_jwks_not_observed, the Wallet did not send a credential proof JWT with header.jwk.
Inspect /sessions/{sessionId}/events and the session raw.proof_headers field to see whether only kid or x5c was present.
Validation
task format
task lint
task test
task build