Skip to main content

Architecture

The credential manager is a three-tier architecture: a static frontend served by Nginx, a Go backend exposing REST and WebSocket APIs, and a trust evaluation sidecar.

Component Roles

Wallet Frontend

A React PWA built with Vite and served by Nginx. The frontend is a static single-page application — all credential protocol logic (OID4VCI issuance, OID4VP presentation) runs in the browser. The backend is used for authentication, credential storage, and protocol proxying.

Runtime configuration is injected at container startup (not baked into the build). A Node.js script reads environment variables and writes <meta> tags and generated files (manifest, theme CSS, well-known endpoints) into the served HTML. This means you configure the frontend entirely through environment variables or Docker build secrets.

Key characteristics:

  • Nginx serves static files on port 80 with SPA fallback
  • PWA with offline support via Workbox service worker
  • WebAuthn-based authentication (no passwords)
  • All credentials encrypted client-side with keys derived from the user's passkey

Wallet Backend

A Go service (Gin framework) that can run as a single process or as separate role-based processes. It provides:

RoleDefault PortProtocolPurpose
backend8080HTTP RESTUser auth, credential CRUD, issuer/verifier metadata, proxy
engine8082WebSocketReal-time OID4VCI/OID4VP session management
admin8081HTTP RESTTenant and user administration (token-protected)
registry8097HTTP RESTVCTM (Verifiable Credential Type Metadata) registry

In a small deployment, run all roles in a single process with --mode=all. For production with horizontal scaling, run each role as a separate container and connect them via external_urls.

Go-Trust

A stateless AuthZEN PDP that evaluates trust decisions against multiple registries. The wallet backend delegates trust checks (e.g., "is this issuer trusted?") to go-trust via the AuthZEN evaluation API. See Go-Trust documentation for full details.

Go-trust has no database — it loads trust data from certificate bundles, trust lists, and federation endpoints at startup and refreshes periodically.

Data Flow

Credential Issuance (OID4VCI)

Credential Presentation (OID4VP)

Network Topology

All three services should be deployed behind a reverse proxy that terminates TLS. A typical setup:

                        ┌─────────────────────────────────┐
│ Reverse Proxy (TLS termination) │
Internet ──── HTTPS ────│ e.g., Caddy, Traefik, Nginx │
└──────────┬──────────┬───────────┘
│ │
┌──────────▼──┐ ┌────▼───────────┐
│ Frontend │ │ Backend │
│ :80 │ │ :8080 (REST) │
│ │ │ :8082 (WS) │
└─────────────┘ │ :8081 (Admin) │
└────┬────────────┘

┌─────────▼─────────┐
│ Go-Trust :6001 │
└───────────────────┘

The admin API (port 8081) should not be exposed to the internet. It is protected by a bearer token and should be accessible only from your management network.

DNS and Origins

The credential manager uses WebAuthn, which binds credentials to a specific origin (scheme + hostname). When deploying on your own domain:

  • The WEBAUTHN_RPID (frontend) and server.rp_id (backend) must match your domain
  • The WALLET_SERVER_RP_ORIGIN must match the exact origin users see (e.g., https://wallet.example.com)
  • Changing the domain after users have registered will invalidate all existing passkeys
Origin Binding

Plan your domain carefully before going to production. WebAuthn credentials cannot be migrated between origins.