Skip to main content

Generated from sirosfoundation/go-wallet-backend's RELEASE_NOTES.md, fetched at build time. Corrections belong in that file, not here.

Wallet Backend Release Notes

[v0.24.0] - 2026-10-19​

Added​

  • Engine now relays credential_metadata from OID4VCI responses, both at the response level (OID4VCI 1.1) and per-credential, preserving extra members verbatim for downstream consumers (#463)
  • Engine requires notification_id when credential_metadata contains a secret seed, ensuring proper tracking of seed delivery (#463)
  • Engine enforces encrypted response delivery when advertising secret_seed capability, preventing accidental plaintext seed transmission (#463)

Fixed​

  • Type assertions throughout codebase are now checked for safety, enabled via errcheck's check-type-assertions linter option (#459)
  • Engine serves valid secret_seed advertisements and drops malformed ones, with capability alignment matching spec 5A requirements (#463)
  • Engine relays credential metadata display data with more generous field capitalization handling to accommodate issuer variations (#463)

Changed​

  • Dependency updates for go modules and GitHub Actions (#464, #465)

[v0.23.0] - 2026-10-15​

v0.23.0 is the same commit as v0.22.4. v0.22.4 was tagged as a patch release but contains breaking changes, so it was re-released under a version that signals the break; v0.22.4 is superseded and should not be deployed. The notes below were first generated under v0.22.4.

Security​

  • Token revocation now enforced. The token blacklist (written by logout) is now actually checked on every authenticated request. Previously, AuthMiddleware hardcoded a nil blacklist, and the /user/session/logout route was never registered, so revoked tokens remained valid until expiry. Both the legacy HMAC path and the AS-issued JWT path now honor revocation. (#391)
  • Refresh-token family revocation. Logging out now revokes every token in the same refresh-token family (all tokens descended from the same original login), not just the one presented. Deleting a user revokes all their tokens immediately. (#391, #402, #414)
  • Verifier trust now PDP-first, fail-closed. When a verifier PDP is configured, evaluateVerifierTrust calls it directly instead of asking the frontend. A PDP error (e.g. evaluator construction failure) now fails closed (untrusted) and never falls back to client-asserted trust. Only PDP-backed verdicts are cached; client-asserted verdicts are never written to the cache. The cache is now keyed by verified identity (DID, x5c-verified client_id, attested sub) instead of a bare URL, so one verifier's cached entry cannot answer for a different verifier sharing the same response_uri. The cache lookup now happens after request-object signature verification. (#389, M-3 HIGH)
  • Issuer trust fail-closed on PDP error. evaluateTrust in oid4vci.go no longer downgrades to frontend-mediated trust when a configured issuer PDP errors. Plain-JSON issuer metadata's credential_issuer claim is now validated against the requested issuer URL. (#387, M-5 MEDIUM)
  • Passkey routes now tenant-gated. /auth/passkey/{login,register}/* previously derived the tenant from the request body with no validation. These routes now enforce X-Tenant-ID via TenantHeaderMiddleware and honor oidc_gate configuration. Registration enforces bind_identity up front; login re-validates audience and required claims against the credential's real tenant. FinishRegistration rejects if the header tenant doesn't match the tenant recorded on the challenge. (#386, M-2 HIGH)
  • OIDC login hardened. The AS's OIDC RP flow now validates that the discovery document's issuer matches the requested issuer, uses PKCE (S256) end-to-end, requires https:// issuer URLs (unless http_client.allow_http is set), and binds the state parameter to a signed HttpOnly/SameSite=Lax cookie to prevent login CSRF. The admin claim (groups/roles containing "admin") only mints elevated permissions when oidc_gate.trust_admin_claim: true is explicitly set. Both Login and Callback now reject disabled tenants. (#390, M-1 HIGH / M-4 MEDIUM / T-4 LOW)
  • DID resolution and x509 verification gaps closed. The DID-scheme frontend fallback now sets requires_resolution: true and request_jwt correctly. x509_san_uri request-object verification now runs before the metadata fetch. x509_san_dns/x509_san_uri/x509_hash now send the properly prefixed client_id_scheme: subject to go-trust's PDP so certificate SAN/hash binding is actually verified. (#401, #413, follow-ups to #389)
  • WebSocket sessions closed on account deletion. DeleteUser now closes live WebSocket connections for that user immediately, not just the persisted session bookkeeping. (#399, #393)
  • Atomic challenge and invite consumption. One-time WebAuthn challenges and invite codes are now consumed atomically (find-and-delete), closing a TOCTOU window where concurrent requests could reuse the same challenge or invite. FinishRegistration now marks the invite completed before creating the user account. Clone-authenticator warnings (sign-count regression) are now logged and emitted as audit events. (#388, W-2 HIGH / W-1 MEDIUM / W-3 LOW)
  • Tenant-mismatch gap in /user/* registration closed. FinishWebAuthnRegistration now rejects if the header tenant doesn't match the tenant recorded on the challenge. (#400, #395)
  • OIDC gate audience and required-claims binding for /user/* login. FinishWebAuthnLogin now populates OIDCGateBinding.Audience and OIDCGateBinding.Claims, so FinishLogin re-validates against the credential's real tenant's audience and required claims, closing a gap where a token valid for one tenant's app could satisfy another tenant's login gate if they shared an issuer. (#412, #408 / #409)
  • Delegation token exchange now audience-checked. The parent token in a delegation request is now verified against cfg.AS.Audiences and checked against the blacklist before a fresh token is minted. (#391, T-1 MEDIUM)
  • OIDC discovery and token exchange now SSRF-guarded. The AS's OIDC login flow and passkey OIDC gate now use HTTPClientConfig.NewIdPHTTPClient, which enforces the same address/scheme policy as other outbound requests plus a new http_client.trusted_idp_hosts allowlist for IdPs that resolve to private addresses. Cloud metadata and unspecified addresses remain blocked. (#419, #349)
  • Rate limiting for OIDC gates. New per-IP (30 attempts/60s, 60s lockout) and per-tenant (300 attempts/60s, 60s lockout) rate limits protect the OIDC gate middleware. Enabled by default; configure via security.oidc_gate_rate_limit. A request carrying a bearer token that the gate refuses costs the client three tokens total. (#425, #65)
  • Opt-in audit events for identity binding. New audit.identity_events config (comma-separated: bound, verified, mismatch, gate_bypass) emits SET events for enterprise identity binding flows. Subjects are hashed. Default empty (no events). (#424, #66)

Added​

  • Configurable WebSocket ping interval. server.engine_ws_ping_interval / engine_ws_pong_timeout (default 3s/5s) replace the hardcoded 30s interval. The server tells the client the interval in HandshakeCompleteMessage.config.ping_interval_ms. (#367)
  • Verifier trust cache can be disabled. trust.cache_disabled and trust.cache_ttl_seconds allow turning off the verifier trust cache or overriding the one-hour TTL, useful for testing environments where a PDP is briefly unreachable or a whitelist is being fixed. (#350, #344)
  • Refresh token route wired up. POST /user/session/refresh is now registered and reachable (previously dead code). (#400, #392)
  • DCQL consent-level subset check. New presentation.dcql_consent_check (off / warn (default) / enforce) validates that the client's consent response fits within the DCQL query sent. In enforce mode, violations block presentation and return access_denied to the verifier. (#428, #140 part A)
  • Registry role reintegrated. The registry can now run as a role within the combined binary (--role registry or WALLET_ROLE=registry), sharing configuration with the wallet/AS. Standalone registry-only mode is still supported. (#431, #430)
  • Issuer metadata type policy. issuer_metadata.metadata_type (prefer-signed (default) / prefer-unsigned / signed-only / unsigned-only / any) replaces the deprecated prefer_signed boolean and metadata_fallback_on_4xx flag. Retries the other media type only on HTTP 406 unless any is set. (#433, #372, #371)
  • Trusted IdP host allowlist. http_client.trusted_idp_hosts (comma-separated hostnames) allows IdPs that resolve to private addresses. (#419, #349)
  • Required-claims CLI support. wallet-admin tenant configure-oidc-gate --required-claims accepts JSON or key=value pairs. (#421, #51 / #52 / #55)
  • Validator cache now bounded. ValidatorCache evicts idle entries after 1h and uses LRU eviction at 256 entries, preventing unbounded growth in long-running processes. (#422, #64)
  • Authentication rejection logging. Both auth middlewares now log rejections at warn level with machine-readable reason, method, path, and client IP. The token itself is never logged. (#416, #301)
  • Session close logging includes session_id. "Session closed" log lines now include an explicit session_id field, matching "Session established", so rapid reconnects can be distinguished from server-side bugs. (#293)

Fixed​

  • Holder DID resolution unified. getHolderDID now consistently prefers user_id over the legacy did claim (AS-issued tokens carry only sub/user_id). (#391, #384 W-5 INFO)
  • Issuer metadata tolerates malformed credential configurations. credential_configurations_supported is now decoded one entry at a time; one undecodable configuration is skipped with a warning instead of failing the whole document. The legacy top-level claims field (when an array) no longer breaks decoding. (#417, #370)
  • Dependency updates. Bumped github.com/gin-contrib/cors to 1.7.9 (Trivy security findings) and github.com/go-webauthn/webauthn to 0.18.2 (attestation trust path, SafetyNet/TPM/FIDO U2F validation, UV authorization). (#369)
  • Legacy password authentication removed. User.PasswordHash, RegisterRequest.Password, bcrypt hashing, and the deprecated UserService.Login() are gone. hasPassword no longer appears in account info responses. Existing password_hash values in MongoDB are ignored on read and dropped on the next write. (#420, #162)
  • Verifier credential_types context preserved. pkg/trust now sends credential_types to go-trust so it is not dropped from the evaluation context. (#442)
  • Reproducible builds. Dropped build-time version injection in favor of runtime resolution to keep builds reproducible. (#443)
  • Verifier IDs passed through to PDP. context.verifier_ids from the authorization request is now preserved in /v1/evaluate and /v1/resolve calls to go-trust. (#455)

Changed​

  • BREAKING: PKCE now required for OIDC login. Any tenant IdP client that doesn't support PKCE will fail token exchange. (#390, #373 M-1 HIGH)
  • BREAKING: Admin-claim gating now opt-in. Tenants relying on an IdP's admin group/role claim to auto-mint elevated permissions must now explicitly set oidc_gate.trust_admin_claim: true. No automated migration is included. (#390, #376 M-4 MEDIUM)
  • BREAKING: HTTPS-only OIDC issuers. Tenant OIDC issuer URLs must now be https:// unless http_client.allow_http is set. Existing http:// issuers are grandfathered until the next config write. (#390, #373 M-1 HIGH)
  • BREAKING: Trusted proxies must be configured for per-IP rate limiting. server.trusted_proxies (IPs/CIDRs or ["none"]) controls whose X-Forwarded-For is believed. Unset keeps gin's trust-everything default (so upgrades don't break) but logs a startup warning while per-IP limiting is enabled. Without it, a direct caller can rotate X-Forwarded-For to dodge the per-IP bucket. (#425, #65)
  • BREAKING: AS audiences now required. as.audiences must be set when the AS is enabled. Legacy HMAC tokens require server.rp_id in the audience list. (#414, go-tokenauth v0.5.0)
  • BREAKING: Registry tokens validated against explicit audiences. The registry now requires as.audiences when auth is enabled, following go-tokenauth v0.5.0. (#431)
  • API: hasPassword removed from account info response. Clients must tolerate the field's absence. (#420, #162)

[v0.22.4] - 2026-10-15​

Superseded by v0.23.0. This release was tagged as a patch release but contains breaking changes (see the v0.23.0 notes above). It is the same commit as v0.23.0. The 0.22 image tag points at a build of v0.22.3, not at this release.

[v0.22.3] - 2026-09-24​

Fixed​

  • Fixed OAuth Client Attestation PoP to include server-provided challenges when required by authorization servers. The engine now detects challenge requirements at PAR and token endpoints, obtains a fresh challenge (from the OAuth-Client-Attestation-Challenge response header or by POSTing the AS's challenge_endpoint), and retries the request with the challenge embedded in the PoP's challenge claim. (#366)
  • Fixed credential issuance to send RFC 8707 resource indicators when the authorization server and credential issuer are on different origins, ensuring the access token's aud claim matches the credential endpoint. (#366)
  • Fixed trust evaluation for verifiers identified by DIDs. The query firewall now permits kid as a resource type, allowing verifiers that sign requests with a kid referencing their DID document to pass authorization checks. Previously, such queries were rejected before reaching the policy decision point. (#363)

[v0.22.2] - 2026-09-23​

Fixed​

  • CodeQL's go/sql-injection exclusion now works correctly using query-filters instead of the previously-inert paths-ignore configuration. This prevents false positives on MongoDB BSON queries, which cannot be exploited as SQL injection since the driver encodes strings as BSON strings and only map keys (not values) can be operators. The filter is safe because this repository has no SQL database usage. (#362)

Changed​

  • Bumped github.com/sirosfoundation/go-trust from v0.20.6 to v0.21.1, adding support for did:jwk resolution, local DID registry configuration (did:key, did:jwk), and accepting kid as DID key binding material for DID-based client_ids. All changes are additive with no breaking changes to imported packages. (#364)
  • Updated Go version requirement from 1.26.6 to 1.27 to match go-trust's minimum version. (#364)

[v0.22.1] - 2026-09-22​

Security​

  • Fixed SSRF vulnerability in POST /helper/get-cert endpoint that allowed authenticated users to probe internal network services and retrieve their TLS certificates, disclosing service topology and internal CA details. The endpoint now applies the same address guard (blocking private/loopback/link-local ranges and cloud metadata endpoints) used by all other outbound fetches. (#358)
  • Fixed crash-loop DoS in WebSocket flow handling where a client-controlled flow_id shorter than 8 characters would panic before the recovery handler registered, killing the process. In combined-role deployments (-mode=all), this could take down backend, engine, registry, and admin services simultaneously. (#357)
  • Updated MongoDB driver to 1.17.10 to address CVE-2026-88031, a GridFS vulnerability where delete methods could match file IDs more loosely than intended, potentially causing unintended deletions. (#356)
  • Kudos to @kushaldas

Changed​

  • Dependency updates: github.com/fxamacker/cbor/v2 and github.com/sirosfoundation/go-cryptoutil/pkcs11pool. (#356)

[v0.22.0] - 2026-09-18​

Added​

  • Authorization details support for DIIP credential issuance. The engine now forwards authorization_details from flow_start to the Authorization Request alongside scope, and honours the credential_identifier echoed by the AS in the token response. This enables wallets to request specific credential configurations when the issuer requires it, without clients needing to construct Authorization Requests themselves. (#341)

  • Admin user detail endpoint at GET /admin/tenants/:id/users/:user_id/detail returns non-PII user information including passkeys, DID, and wallet type. A stub tenant statistics endpoint at GET /admin/tenants/:id/stats returns 501. (#250)

  • Audit events for invite lifecycle. The admin API now emits invite:created, invite:updated (with renew/revoke action), and invite:deleted events to the SET audit trail. (#249)

  • Empty credential match handling. When a presentation request cannot be satisfied because the wallet holds no matching credentials, the flow now ends immediately instead of waiting for the 5-minute timeout. The wallet client receives a NO_MATCHING_CREDENTIALS flow error carrying the requested credential types as data, so it can phrase the explanation in the user's own language. The verifier receives access_denied with the same error_description a user decline sends: OpenID4VP 1.0 answers "the Wallet did not have the requested Credentials" and "the End-User did not give consent" with one code precisely so the two cannot be told apart, and naming the missing types would have let a verifier probe what a holder has. Non-empty match sets remain informational. (#336)

Fixed​

  • SSRF protection gaps in outbound HTTP client. The dialer now connects to an address that was actually checked (closing a DNS rebinding window), applies address policy when requests are proxied (where the dialer cannot see the target), and refuses plaintext HTTP for all fetches unless explicitly configured. Deployments with allow_private_ips, allow_http, or insecure_skip_verify are unaffected; those without any of the three will now reject plaintext public hosts with an error naming the flag to set. (#338)

  • IETF-mode wallet instance attestations missing x5c. WIA JWTs in IETF mode now include the x5c header when certificate material is configured, preserving JWKS-based resolution while adding certificate-chain resolution for consumers that require it. Deployments without a certificate chain continue to work with kid-only headers. (#346)

  • Native wallet credential offers failing to parse. The engine now accepts credential offer URIs with no authority component (openid-credential-offer:?credential_offer=...), matching RFC 3986 and the output of the issuer gateway's native chooser. Previously only the double-slash form was recognised. (#345)

  • OpenID4VP 1.0 verifiers rejected for unrecognised client_id_scheme. The engine now accepts decentralized_identifier (the final specification's name for the DID scheme) alongside the draft spelling did, and strips the prefix when resolving the DID document. Verifiers using the 1.0 identifier format can now be verified. (#343)

Changed​

  • Audit emit failures are now logged rather than silently dropped, using the logger the emitter was constructed with. (#249)

  • verifier:created audit events now use the verifier URL as subject (matching issuer:created), with verifier_id and name in the event data, so create events can be correlated with later updates and deletes. (#249)

[v0.21.0] - 2026-09-16​

Added​

  • Authorization Server cookie sessions can now be persisted in MongoDB instead of only in-process memory, enabling session survival across restarts and multi-instance deployments. Configure via as.session_store / WALLET_AS_SESSION_STORE (defaults to mongodb when MongoDB is the storage backend). (#325)

Fixed​

  • MongoDB-backed issuer, verifier, credential, and presentation stores now correctly mint unique IDs on a fresh database. Previously, the first two entities created would collide on ID 1, causing already exists errors. (#327)
  • Status list test suite now correctly decodes zlib-compressed status lists, matching the production implementation changed in v0.20.0. (#326)
  • Key Attestation certification field is now an absolute URL as required by the specification. (#331)

Changed​

  • Dependency updates: github.com/gin-contrib/cors 1.7.7→1.7.8, github.com/go-webauthn/webauthn 0.18.0→0.18.1, github.com/sirosfoundation/go-trust 0.20.5→0.20.6, golang.org/x/crypto 0.56.0→0.57.0, golang.org/x/sync 0.22.0→0.23.0, golang.org/x/time 0.15.0→0.16.0, github.com/go-jose/go-jose/v4 4.1.4→4.1.5. (#323)
  • CI tooling updated to golangci-lint v2.13.2 for Go 1.26 compatibility. (#321)

[v0.20.0] - 2026-09-10​

Added​

  • Client-held DPoP keys: New sign_client_auth action allows clients to hold their own DPoP private keys instead of the engine generating them. For each authenticated request, the engine now requests fresh signatures (DPoP proofs and wallet attestation PoPs) from the client with request-specific parameters. This ensures cnf == DPoP key because clients use one key for both, and eliminates replay of stale attestations. (#318)
  • Automatic mode detection: The engine probes clients at the first authenticated request and adapts per-flow—client-held mode if the client answers sign_client_auth, legacy mode (engine-generated keys) if the client doesn't respond or times out. Pre-resolved attestations or renewals with dpop_jwk skip the probe and use legacy mode. (#318)

Changed​

  • Renewal flow: in client-held mode flow_complete returns dpop_key_id instead of the private dpop_jwk, and a renewal flow_start sends dpop_key_id back so the engine asks the client to sign with the key the refresh token is bound to. dpop_jwk keeps working for tokens issued by older backends. (#318)
  • Notification endpoint: DPoP-bound notifications now work in both client-held and legacy modes after flow completion by abstracting the signing mechanism. (#318)

Fixed​

  • Documentation: The WebSocket protocol spec now documents sign_client_auth, request_attestation, and renewal fields that were previously undocumented. (#318)

[v0.19.0] - 2026-09-07​

Fixed​

  • OID4VP request encryption now respects the alg header specified in the verifier's JWK instead of always inferring it from the key material, preventing validation failures when the verifier checks the returned vp_token (#315)

[v0.18.4] - 2026-09-07​

This is the first usable release of the 0.18 line. v0.18.1 does not build, v0.18.2 rejects every WebAuthn sign-up and login, and v0.18.3 was tagged on the wrong commit. Deployments on v0.17.0 should move straight here.

Fixed​

  • WebAuthn registration and login now accept PRF (Pseudo-Random Function) extension outputs from clients. After the go-webauthn 0.18 upgrade, both flows were rejecting credentials when clients returned PRF outputs that the backend hadn't explicitly requested, breaking sign-up and authentication for wallets that use client-side PRF salts (#312)

[v0.18.3] - 2026-09-06​

Broken release - use v0.18.4. This tag was created on the wrong commit and contains the same code as v0.18.2, including the WebAuthn sign-up and login failure fixed in v0.18.4. No container image was published for it.

Changed​

  • Updated release notes documentation for v0.18.2 (#311)

[v0.18.2] - 2026-09-06​

Do not deploy - use v0.18.4. WebAuthn sign-up and login fail on this release with Client returned the "prf" extension output which was not requested; v0.18.4 fixes it and delivers everything listed here.

Use this instead of v0.18.1. v0.18.1 does not compile and produced no container image; everything it lists is delivered here.

Fixed​

  • Restored compilation against go-webauthn 0.18 by updating the VerifyAttestation call site to pass the two new policy arguments required by the library's API change. The signature policy explicitly selects BER encoding tolerance to maintain support for YubiKey firmware 5.8's non-minimally-encoded ECDSA signatures, which would otherwise be rejected by 0.18's stricter DER-only default (#310)

[v0.18.1] - 2026-09-06​

Broken release - use v0.18.2. The go-webauthn 0.18.0 bump below changed an API whose call site was not updated, so this tag does not build and no image was published for it.

Fixed​

  • Increased signing timeout from 30 seconds to 3 minutes to accommodate zero-knowledge proof operations on slower devices (#300)
  • -mode all now starts every role. It expanded to a hardcoded list of five, silently omitting storage and wallet-provider, so a deployment that asked for every role was not running those two; it now expands to ValidRoles. The -mode help text also lists every role rather than three (#290)

Changed​

  • Updated dependencies: go-webauthn/webauthn to v0.18.0 (adds Post-Quantum Cryptography support), golang.org/x/crypto, and getkin/kin-openapi (#308)

[v0.18.0] - 2026-09-06​

Added​

  • Issuer entitlement verification implementing ARF v3.0.0 §6.6.2.3 and CIR (EU) 2025/848 requirements. The /v1/resolve endpoint now evaluates an issuer's access certificate (WRPAC) and registration certificate (WRPRC) to determine whether the issuer is entitled to issue what it offers, returning an issuer_entitlement decision alongside metadata. Controlled by ISSUER_ENTITLEMENT_MODE environment variable (warn by default, fail, or off). The default warn mode logs violations without blocking issuance, reflecting the 24-month grace period before ARF registration obligations take effect. (#306)

[v0.17.0] - 2026-09-04​

Added​

The engine now asks the client for its Wallet Instance Attestation at the point where it can actually be built (#304). The per-flow OAuth-Client-Attestation-PoP has to name the issuer's authorization server as its aud, and that server is only known after the credential offer and issuer metadata have been resolved. A browser wallet cannot resolve a cross-origin credential_offer_uri itself, so it could never compute the audience before starting the flow; the native SDKs only managed it by duplicating the backend's discovery on the device.

The OID4VCI engine therefore sends a new sign_request action, request_attestation, right after metadata resolution whenever FlowStart did not already carry client_attestation and client_attestation_pop. Its params are audience (the authorization server URL, for the PoP aud) and issuer (the effective client_id, for the PoP iss); the client answers with client_attestation and client_attestation_pop in its sign_response, or with neither to proceed without attestation. Attestation supplied up front on FlowStart is still honoured and takes precedence. The instance key never leaves the client.

Client compatibility. A client that predates this action does not answer the request. The engine waits at most 10 seconds for it (not the general 30 second signing timeout) and then continues without attestation, so older wallet-frontend and SDK builds keep working with a one-off delay per issuance until they are updated. The companion changes are wallet-frontend#196, siros-sdk-kotlin#154 and siros-sdk-swift#122; the follow-ups that drop the SDKs' own discovery (siros-sdk-kotlin#155, siros-sdk-swift#123) must not ship before this release is deployed.

[v0.16.0] - 2026-09-02​

Fixed​

Wallet Unit Attestations now carry the status claims CS-04 requires (#302). The WIA was missing client_status and the Key Attestation was missing key_storage_status, both mandated by WE BUILD CS-04 §7.1.2/§7.1.3 (TS-03 clauses 2.3.1/2.3.2). A conformant PID or Attestation Provider rejects a WUA without them, which is exactly what the WE BUILD ITB testbed did: invalid_proof: WUA signature verification failed: Key Attestation missing required key_storage_status. Take this release before any interop run against a CS-04-conformant issuer.

The claims were removed in v0.13.0 (#261) on the grounds that this wallet provider implements no revocation-chaining. That reasoning still holds — short attestation lifetimes, not a revocation list, are what bound exposure here — but it conflated not revoking through a status list with being allowed to omit the claims that reference one. Both now reference the wallet provider's own Token Status List, which is served all-VALID and never has a bit set; the config comments and docs/wallet-instance-attestation.md say so plainly rather than implying a revocation capability that isn't there. KA indices follow CS-04 §7.2.3 Option 1 (type-shared, one per keystore tier), and a mixed batch is indexed by its weakest tier so an issuer is never told the batch is better protected than it is.

A deployment that would rather advertise no revocation mechanism than an inert one can set wallet_provider.attestation.status_list.enabled: false and go back to omitting the claims, at the cost of CS-04 conformance. The reference URI defaults to <server.base_url>/wallet-provider/status-list, and the maintenance exp defaults to 45 days — deliberately not the 31-day floor, since CS-04 §7.2.2 requires those 31 days to still be remaining at presentation, not at issuance.

  • The Key Attestation also emitted no key_storage, user_authentication or certification at all when the client omitted security_properties, and could still drop user_authentication for a trusted client that reported "none". All three are required on every KA, so each now falls back to the weakest value in the ISO 18045 vocabulary rather than being left absent — a floor never overstates what the client claimed. (#302, with fixes from @Didr)

[v0.15.2] - 2026-08-31​

Fixed​

  • OID4VP presentation requests using client_id_scheme=x509_hash are now accepted. Previously the wallet rejected all such requests with "Invalid message format" because the scheme was missing from the allowlist, breaking interoperability with verifiers like NIST's OpenID4VP reference implementation. (#298)

[v0.15.1] - 2026-08-30​

Fixed​

  • Fixed OID4VP presentation flows incorrectly reporting "Could not parse credential offer" (an issuance error) when the actual failure was fetching or parsing the presentation request from a verifier's request_uri. Now returns a distinct "Could not parse the presentation request" error code. Also logs the response body (capped, at Debug level) when a request_uri fetch fails, making it possible to distinguish expired verifier sessions from network errors without reproducing the failure separately (#294)
  • Fixed mdoc issuance flows being blocked with 403 errors during issuer-trust evaluation. The authorization proxy's allowlist included mdoc-reader-auth (for presentation) but was missing the issuer-side mirror mdoc-issuer-auth, causing all VICAL issuer-trust queries to be denied before reaching the policy decision point regardless of issuer identity (#296)
  • Fixed --mode registry panicking on startup when CORS origins list is empty. Now handles empty configuration gracefully and warns when wildcard CORS is combined with AllowCredentials (#292)

Changed​

  • Updated to go-trust v0.16.0, which adds support for loading additional trusted roots via YAML configuration (#288)
  • Updated Go runtime to 1.27 stable (#287)
  • Updated dependency group including testify, cbor, and kin-openapi (#288)

[v0.15.0] - 2026-08-24​

Fixed​

Key Attestation JWTs now carry the spec-registered typ (#289). The JOSE header said keyattestation+jwt, the pre-1.0 draft spelling; OpenID4VCI 1.0 registers the media type as application/key-attestation+jwt (Appendix G.6.2), and the JOSE typ carries the short form key-attestation+jwt, hyphenated. Issuers pin this exactly and reject the whole credential request rather than falling back to the jwt proof type. Because a wallet picks its proof type per issuer rather than per credential, this failed every credential type at once against any issuer advertising the attestation proof type. The error was invisible from the client, which only ever saw the sanitized "Credential issuance failed". This release is worth taking before bumping any issuer image past 2026-08-19, the point at which SUNET/vc began advertising attestation alongside jwt for every scope. Deployments pinned to an older issuer were unaffected only because their issuer never offered the attestation path.

Changed​

GET /issuer/:id/metadata embeds the issuer's own images as data: URIs (#284). A logo or SVG template hosted somewhere that sends no Access-Control-Allow-Origin is unusable by a browser wallet, which fetches the SVG to substitute claim values into it and renders a broken image. The endpoint now runs the issuer's own credential_configurations_supported through the existing image embedder, which removes the cross-origin fetch. Only asset delivery changes — nothing is substituted from the VCTM registry, so the response remains the issuer's own content. Failure is soft by construction: an image too large (>1 MB), too slow (>10 s) or unreachable leaves the issuer's original URL in place, exactly as before. Note that only https:// image URLs are embedded, so an all-HTTP local development stack sees no change.

[v0.14.1] - 2026-08-21​

Fixed​

  • HTTP issuer resolution now works when allow_http is enabled (#282). Previously, resolving a plain-HTTP credential issuer (subject_type: "url") failed even with allow_http configured — the scheme validation in Resolve() hardcoded HTTPS regardless of the flag, and the authorization rules lacked an HTTP variant for credential_issuer queries. Both layers now honor the allow_http setting. HTTPS-only remains the default.

  • PAR failures are now surfaced immediately when the Authorization Server requires PAR (#280). Previously, any Pushed Authorization Request failure triggered a silent fallback to a standard /authorize request with inline parameters. For an AS that mandates PAR (require_pushed_authorization_requests: true), this fallback is guaranteed to fail with a confusing downstream error instead of showing the real PAR failure reason. The client now checks the AS metadata and surfaces the actual PAR error immediately when PAR is required, while preserving the fallback for ASs that support PAR optionally.

Changed​

  • TS11 schema fetching delegated to go-ts11client (#281). The processTS11Response logic for fetching and paginating /api/v1/schemas.json now uses the shared github.com/sirosfoundation/go-ts11client library instead of maintaining duplicate implementations. Legacy registry formats, the multi-source overlay model, and per-item skip logging remain unchanged.

[v0.14.0] - 2026-08-20​

Added​

  • New mdoc-reader-auth action is now permitted in the default SPOCP authorization policy, enabling SDK reader-trust checks (subject type key, resource type x5c) to pass through /v1/evaluate without requiring a custom rules file (#279)

Fixed​

  • Resolved crypto/ecdsa deprecation warnings (Go 1.26+) by migrating from direct field access (PublicKey.X/Y, PrivateKey.D) to the new ECDH() API in OID4VCI, JWKS, and JWT utility code (#279)

Changed​

  • Configuration documentation (docs/CONFIGURATION.md) is now enforced to stay in sync with code via CI — builds fail if the generated doc drifts from the config structs, preventing silent staleness (#278)

[v0.13.0] - 2026-08-18​

Added​

  • Forward verifier session ID to sign_presentation to enable correct ZK verifier_context derivation for pairwise-pseudonym presentations (#277)

Fixed​

  • Raise wallet→backend WebSocket message read limit to accommodate ZK proofs, which were previously larger than the connection's default cap and could not be sent (#277)
  • Pre-authentication read-limit bypass: unauthenticated clients could previously force repeated multi-MB allocations by exploiting the larger message cap applied before handshake/auth checks; now capped at 64KB until token validation completes (#277)
  • JWT/JSON request-body misclassification that could incorrectly identify a JSON body containing a URL-like field as a JWT (#277)

Changed​

  • Dependency updates: Go toolchain and Docker builder base images (#275, #276)

[v0.12.0] - 2026-08-14​

Added​

  • OID4VCI credential renewal support: the backend now relays refresh_token from issuers to clients and implements a renewal-request engine action that reuses the wallet's persistent credential-holder-binding key to satisfy EUDI ARF ISSU_65 continuity requirements (#273, #274)

Fixed​

  • Deduplicated OID4VCI token-exchange grant handling and clarified cross-repository issue references (#274)

Security​

  • Upgraded Go toolchain to 1.26.6, resolving 5 standard library CVEs that were blocking the vulnerability-check gate (#274)

[v0.11.1] - 2026-08-14​

Changed​

  • Default JWE content-encryption algorithm for direct_post.jwt responses changed from A128CBC-HS256 to A128GCM when verifiers don't declare authorization_encrypted_response_enc in their client metadata. Improves interoperability with verifiers that only implement the GCM cipher family (e.g., multipaz), while remaining spec-compliant. (#272)

[v0.11.0] - 2026-08-11​

Added​

  • Per-route TAC (Token Access Control) enforcement across all HTTP and WebSocket routes. Previously, any authenticated token could access all routes regardless of its tac claim. Routes now require specific TAC values: r (read), w (write/mutate), l (list), i (create), or d (delete). WebSocket flows enforce r for OID4VP presentation and i for OID4VCI issuance. Legacy HMAC authentication (which has no TAC concept) continues to work unchanged. (#264)
  • FIDO2/CTAP2 hardware attestation is now recognized as key attestation trust evidence for WIA flows, verified against the go-trust root store rather than pinned CAs. Attestation evidence is stored per-key (not instance-level), and attestation level-of-assurance is surfaced in type-metadata responses. (#266, #267)

Fixed​

  • haip-vp:// scheme (HAIP 1.0 final) is now recognized in OID4VP request-URI parsing. Previously only openid4vp:// and the draft haip:// were accepted, causing real verifier requests to fail with "invalid message format" instead of dereferencing the request. (#270)

Security​

  • Upgraded go-tokenauth to v0.4.0, which fixes two vulnerabilities reachable through JWKS fetch: a crypto/tls ECH privacy leak (GO-2026-5856) and a quic-go HTTP/3 QPACK memory-exhaustion bug (GO-2026-5676). (#268)
  • Dependency updates: go-redis/v9 9.21.0 → 9.22.0 and kin-openapi patch bump. (#271)

[v0.10.1] - 2026-08-06​

Fixed​

  • Key Attestation nonce compatibility: The attestation proof type now sends both c_nonce and nonce claims to the credential endpoint, fixing issuance failures with providers (like geneva2026.mdoc.online) that expect nonce rather than the TS03-specified c_nonce. An unrecognized extra claim is harmless to conformant verifiers. (#265)

Changed​

  • SPOCP delegation policy documentation: Replaced misleading read-only rules in delegation.rules with documentation clarifying that delegation intentionally supports downscoping to any subset of the parent token's capabilities (including write/delete/re-delegation), not just read operations. The actual security boundary—delegated capabilities must be a subset of the delegating token's capabilities—remains enforced in code as before. No behavior change. (#263)

[v0.10.0] - 2026-08-06​

Added​

  • Wallet-attestation-based OAuth client authentication: Clients can now authenticate to the Authorization Server using a self-attested Wallet Instance Attestation (WIA) instead of pre-registered credentials, per draft-ietf-oauth-attestation-based-client-auth. The AS auto-enables for --mode=auth deployments, reusing the wallet provider's signing key and bundled SPOCP policy unless explicitly configured otherwise. (#259)
  • IETF/ETSI mode split for WIA/Key Attestation: New wallet_provider.wia.mode setting (etsi/ietf) controls whether WIA uses x5c-based trust (ETSI TS 119 472-3, EC TS03 v1.5.2) or JWKS-based trust (IETF draft). ETSI mode requires a certificate; IETF mode works with a signing key alone. A bare-root /.well-known/jwks.json route now serves the wallet provider's public key for JWKS-based trust resolution. (#261)
  • Audience-based token scoping: Anonymous tokens (issued for trust-evaluation workflows) are now restricted to wallet-registry/wallet-backend audiences and rejected on identity-bearing routes. AuthZEN proxy and engine transport routes require one of those audiences; general user-facing routes require wallet-backend. (#262)

Fixed​

  • Authorization Server metadata unreachable via AuthZEN proxy: The /v1/resolve endpoint's allowlist rejected resource_type=oauth-authorization-server queries before reaching the handler that explicitly supported them, breaking PAR-endpoint discovery for wallets. The allowlist now includes oauth-authorization-server. (#260)
  • SPOCP wildcard rules never matched: Rules loaded from .rules files used canonical netstring format, which parsed wildcards as ordinary empty lists instead of actual wildcards—causing every wildcard rule to silently deny all queries. Rules now load in advanced form ((tac (*)) syntax) and are duplicated per query shape (with-acr, without-acr, anonymous) to align with go-spocp's positional field matching. (#258)
  • Nil-pointer panic on --mode=auth: Running the server with --mode=auth alone would panic at startup because the AS's EnableForRole() call expected a config that was only loaded for other roles. RoleAuth is now included in the config-load condition. (#259)
  • Missing JWKS route in standalone wallet-provider mode: Deployments running --mode=wallet-provider as a separate microservice had no way to serve their JWKS. The JWKS route is now wired into both co-hosted and standalone modes. (#259)

Changed​

  • WIA/Key Attestation aligned with EC TS03 v1.5.2 and ETSI TS 119 472-3: Removed client_status/key_storage_status claims (no revocation-chaining support); WIA lifetime now defaults to 5 minutes. Fixed the Key Attestation's nonce claim (c_nonce) and removed its stray iss claim. Corrected the attestation_source claim's citation to reference the SIROS extension mirroring the open Annex C PR to WP4 CS-04. (#261)
  • Config validation tightened: wallet_provider.wia.omit_x5c: true (now superseded by mode: ietf) is rejected if no wia.issuer is set, preventing silent misuse of wallet_provider_uri as a JWKS-discovery URL. (#259)

[v0.9.1] - 2026-08-04​

Security​

  • Key Attestation requests no longer accept self-asserted security properties. The key_storage, certification, and user_authentication claims in keyattestation+jwt are now clamped to software-level defaults (iso_18045_basic / "none") unless the request's wallet_instance_id resolves to a wallet instance whose WIA was backed by verified native platform attestation (iOS App Attest or Android Play Integrity). Previously, any caller could claim hardware-level security (e.g., key_storage: ["iso_18045_high"]) and have it signed without verification, undermining relying parties' Level of Assurance decisions. (#256)

Fixed​

  • Key Attestation now normalizes internal WSCD vocabulary (software/hardware/trusted_execution/remote_hsm) to the registered ISO 18045 enum (iso_18045_basic/iso_18045_moderate/iso_18045_high) before signing. Previously, raw internal values were likely being emitted in production attestations, producing non-compliant claim values. (#256)

[v0.9.0] - 2026-08-04​

Added​

  • Wallet Instance Attestation (WIA) issuance per CS-04 §7.1.2 and §7.1.4: new /wallet-provider/wia/challenge and /wallet-provider/wia/generate endpoints issue single-use, PoP-bound WIA JWTs signed with the wallet-provider key and including x5c chains, cnf binding to the instance DPoP key, and Tier 3 baseline attestation claims. (#221)

Fixed​

  • OpenID4VP engine now correctly handles haip://-scheme requests (High Assurance Interoperability Profile) and fetches bare reference-URL requests (e.g., .../haip-vp links with no query string) instead of treating them as empty by-value requests. (#255)
  • WIA issuance now rejects suspended or revoked wallet instances; previously Upsert unconditionally reset status to Active, allowing revoked instances to re-attest and obtain fresh credentials. (#221)
  • MongoDB WIA challenge store is now correctly selected for horizontally-scalable deployments; the Database() method was never forwarded, causing all MongoDB backends to silently fall back to the single-instance in-memory store. (#221)
  • WalletInstance.UserID is now populated during WIA issuance, fixing the previously-empty results from GET /admin/tenants/:id/users/:user_id/instances. (#221)
  • WebSocket and session connection limits now count every upgraded connection from open to close and reserve slots atomically, preventing both unauthenticated-connection bypass and check-then-increment races under concurrent load. (#221)
  • Isolated wallet-provider mode now accepts AS-issued tokens instead of rejecting them with hardcoded legacy HMAC auth. (#221)
  • PKCS#11 key-loading failures now correctly fall back to configured file-based keys instead of stopping at the first failure. (#221)
  • Pre-authorized code token exchange now sends client-attestation headers, matching the PAR and authorization_code flows; wallets using attestation-based auth previously had no client authentication on this (most common) flow. (#221)
  • Play Integrity decryption/verification keys now support *_path file-based loading, consistent with other secrets in the configuration. (#221)

[v0.8.0] - 2026-07-28​

Added​

  • Registry support for mso_mdoc credentials alongside sd-jwt VCTM: local overrides, dynamic fetch, and TS11/registry polling now recognize doctype-identified MDDL documents in addition to vct-identified VCTM ones. When a TS11 schema offers both formats, both are now cached and served instead of silently dropping the mdoc variant. (#254)
  • Verifier client_id_scheme support: verifiers can now identify themselves via DID, OpenID Federation entity statements, or X.509 attestation, enabling trust evaluation of the verifier before credential presentation. (#237)
  • Server-side issuer trust evaluation: when a go-trust PDP URL is configured, the wallet backend now evaluates issuer trust directly without requiring frontend mediation. Falls back to the existing frontend-mediated flow when no PDP is configured, ensuring backward compatibility. (#239)

Security​

  • Workflow tokens now use least-privilege permissions (contents: read by default, with explicit job-level write grants only where needed), addressing OpenSSF Scorecard token-permissions requirements. (#245)

Changed​

  • Replaced sunset Go Report Card badge with OpenSSF Scorecard badge, which reports on security best practices including branch protection, CI configuration, and dependency management. (#244)
  • CI workflows can now be triggered manually via the Actions UI (workflow_dispatch), enabling ad-hoc builds from any ref. (#242)
  • CodeQL configuration now excludes MongoDB BSON query construction from SQL injection analysis (parameterized NoSQL queries are not vulnerable to the same injection patterns as string-concatenated SQL). (#247)

[v0.7.1] - 2026-07-08​

Fixed​

  • JARM encryption algorithm inference for direct_post.jwt response mode (#235) — When response_mode=direct_post.jwt is used but authorization_encrypted_response_alg is absent from client_metadata, the wallet now infers the encryption algorithm from the verifier's public key material (EC key → ECDH-ES, RSA key → RSA-OAEP) instead of failing with "An error occurred during credential verification". This fixes interoperability with x509_san_dns verifiers using ETSI TS 119 411-8 access certificates, such as Sikt and SUNET deployments.

  • OID4VCI/VP conformance test failures (#232) — Fixed RFC 8414 OAuth AS metadata URL construction (trailing slash handling), added support for the authorization_servers array field (OID4VCI 1.0 Final), and corrected negative-test behavior to silently reject invalid authorization requests rather than POST error responses. VCI conformance improved from 0/4 to 4/4 passed; VP negative tests now correctly reject invalid requests.

Changed​

  • Sensitive route cache headers (#187) — Auth, session, and credential storage endpoints now emit Cache-Control: no-store, no-cache, must-revalidate headers to prevent browser or intermediary caching of sensitive wallet state and encrypted private data.

Security​

  • Go 1.26.5 upgrade — Fixes GO-2026-5856, an Encrypted Client Hello privacy leak in crypto/tls.

[v0.7.0] - 2026-07-03​

Added​

  • Key Attestation security properties: Key Attestation JWTs now include key_storage, user_authentication, and certification claims describing WSCD security characteristics. Callers can optionally provide these properties when generating attestations, enabling verifiers to assess key protection levels. (#219)
  • Transaction data relay for payment SCA: OID4VP authorization requests now parse and relay the verifier's transaction_data array through to the frontend sign request. This allows the SDK to bind transaction details into the key binding proof, satisfying EUDI TS12 payment strong customer authentication requirements. (#220)
  • Authorization Server with session-based tokens: Complete Authorization Server implementation (internal/as/) replacing legacy HMAC tokens with short-lived JWT sessions (default 2 min TTL). Includes JWKS endpoint, SPOCP policy-based authorization with per-audience TAC (token access control) permissions, delegation token issuance with subset enforcement, OIDC authentication, WebAuthn passkey scaffolding, and session management with secure cookies. Legacy token mode remains available during migration with configurable sunset schedule. (#229)

Security​

  • OIDC host header injection fixed: Authorization Server OIDC flows now use configured ExternalURL instead of the Host header for redirect URIs, preventing attacker-controlled redirects. (#229)
  • OIDC nonce validation: OIDC state parameter now includes a SHA-256 nonce challenge verified on callback to prevent replay attacks. (#229)

Changed​

  • Dependency updates: go-redis/v9 9.20.0→9.20.1 (fixes RESP3 pub/sub message loss), golang.org/x/crypto, golang.org/x/net. (#217)
  • CI updates: actions/checkout v4→v7, ossf/scorecard-action, SonarSource/sonarqube-scan-action. (#216)
  • Base container image: Alpine 3.23→3.24. (#215)

[v0.6.1] - 2026-06-14​

Fixed​

  • Preserve trailing slashes in issuer identifier paths when constructing well-known URLs, fixing metadata discovery failures with external issuers (like the OIDF Conformance Suite) that include trailing slashes in their credential_issuer identifier per RFC 8615 (#214)

[v0.6.0] - 2026-06-10​

Added​

  • Resource-type routing for /v1/resolve endpoint: oauth-authorization-server now resolves AS metadata via RFC 8414 well-known discovery, and credential_offer_uri fetches and validates OID4VCI credential offers server-side (#170, #153)
  • Forward optional credential_types array through /v1/resolve to upstream PDP as action.parameters.credential_types for credential-type-specific trust evaluation (#198)
  • Configuration reference generator (make gen-config-docs) that produces docs/CONFIGURATION.md from Go config structs, covering 166 fields across backend and registry server (#172)
  • WebSocket engine stress tests covering 13 scenarios: expired tokens, concurrent flow limits, session replacement, rapid reconnect, malformed messages, and slow sign responses (#170)
  • Debug logging for WebAuthn credential assertion responses with increased preview limit to capture relevant parts (#181)
  • Forensic fingerprints (SHA-256 hashes of auth data, client data, signature, and x5c leaf) in WebAuthn registration and login error paths to help diagnose intermittent attestation verification failures (#188, #197)
  • OpenAPI spec route coverage test to ensure all admin API endpoints are documented (#201)
  • SonarCloud and OpenSSF Scorecard CI workflows for continuous code quality and supply-chain security analysis (#204)
  • Registry server support for TS11 paginated API format with mode config field (ts11 or registry) to select between legacy and new formats (#174)
  • Support for did:web credential issuers: subject_type=key with resource_type=credential_issuer now converts DID to URL and resolves issuer metadata (#206, #208)

Fixed​

  • DPoP JTI reuse on token endpoint use_dpop_nonce retry: each retry now generates a fresh client_assertion JWT with unique JTI (#170)
  • Issuer metadata resolver cache misses caused by trailing slash inconsistency: URLs are now normalized before cache lookup (#170)
  • Conformance workflow security: replaced inline shell logic with centralized composite action, fixing GITHUB_OUTPUT injection vulnerability and adding variant-filter support (#185)
  • OpenAPI admin spec alignment: added missing require_invite, trust_config, oidc_gate, verifier client_id/client_id_scheme, and trust status fields; documented OIDC gate modes and verifier client ID schemes; bumped spec to v1.1.0 (#159)
  • Scorecard workflow permissions: replaced read-all with explicit minimal permissions (contents: read, actions: read) to address SonarCloud security hotspot (#205)
  • CVE-2026-40898: bumped quic-go to v0.59.1 to fix connection migration DoS vulnerability (#207)

Changed​

  • Registry integration tests now gated behind integration build tag so go test ./... runs only fast unit tests (#174)
  • Upgraded OpenAPI spec from 3.0.0 to 3.1.0 for if/then schema support (#201)
  • MongoDB tests now gated behind environment variable to avoid requiring MongoDB for default test runs (#201)
  • Dependency updates: go-webauthn 0.17.3→0.17.4, go-trust 0.4.1→0.6.0, go-redis 9.19.0→9.20.0, codecov-action 6→7 (#184, #189, #203, #209)

[v0.5.2] - 2026-05-18​

Fixed​

  • Registry server now reads JWT secrets from files. The registry's JWTConfig only supported inline jwt.secret, causing JWT secret is empty errors when deployments used jwt.secret_path (common in Docker/Kubernetes with mounted secrets). Now matches the main backend's behavior by reading the file during validation. (#175)

  • JWT validation no longer rejects tokens due to clock skew. Added 5-second leeway to nbf (not-before) and exp (expiration) checks in both engine and legacy WebSocket handlers. Previously, tokens could fail validation within the same second they were issued due to strict timing or minor clock differences between containers. (#176)

  • WebSocket connections no longer fail after 15 seconds. Cleared the stale write deadline inherited from net/http's WriteTimeout immediately after WebSocket upgrade. Without this fix, all writes to upgraded connections would fail once the deadline elapsed. Affects both engine and legacy handlers. (#178)

  • X-Served-By header restored to all responses. The middleware was lost during server refactoring and has been re-wired into the unified router. This header identifies which instance served each request, critical for debugging multi-replica deployments. (#179)

  • X-Served-By header now appears on WebSocket upgrade responses. Gin middleware cannot inject headers after gorilla/websocket hijacks the connection, so the header is now explicitly passed to the upgrader in both WebSocket handlers. (#180)

Changed​

  • Go runtime updated from 1.26.2 to 1.26.3 in go.mod and Dockerfiles for reproducible builds. (#180)

[v0.5.1] - 2026-05-15​

Fixed​

  • Fixed private_key_jwt client authentication to include the kid header in JWT assertions and use the correct aud claim value, ensuring proper token endpoint authentication (#590b3d44)
  • Preserved trailing slashes in well-known URIs to maintain strict RFC compliance when resolving OAuth/OIDC metadata endpoints (#dac5ecb8, #0b4df038)
  • Removed redundant format and vct parameters from credential requests that were causing validation failures with some issuers (#0b4df038)

[v0.5.0] - 2026-05-15​

Added​

  • Prometheus metrics — HTTP request counters and latency histograms exposed on /metrics, with /healthz endpoint for Kubernetes probes (#89)
  • Local VCTM overrides — Load credential type metadata from local JSON files that take precedence over remote registry entries (#120)
  • Issuer metadata endpoint — GET /issuer/:id/metadata fetches OpenID4VCI metadata server-side for authenticated users, avoiding WebSocket proxy limitations (#123)
  • DCQL query support — OID4VP flows now accept DCQL queries for credential selection; Presentation Definition support removed in favor of DCQL-only (#128)
  • Multiple WebAuthn RP origins — rp_origins config field enables native app wrappers (Android/iOS) to register alongside web frontends (#144)
  • URL-based issuer resolution — /v1/resolve endpoint accepts HTTPS issuer URLs alongside DID-based subjects, with local metadata resolution and registered issuer enrichment (#131, #151)
  • TS11 schemas API support — Registry client migrated from legacy .well-known/vctm-registry.json to /api/v1/schemas.json with full pagination and multi-registry merging (#141)
  • JWKS retry and circuit breaker — Token validation now retries transient IdP failures with exponential backoff and falls back to stale cache when circuit opens (#160)
  • WebSocket keepalive — Server-side ping/pong prevents mobile network idle disconnects after 15 minutes (#165)
  • OID4VCI Nonce Endpoint — Support for dedicated nonce endpoint per OID4VCI 1.0 final spec, with backward compatibility for token-response nonces (#166)
  • private_key_jwt client authentication — OID4VCI flows can now authenticate to token endpoints using signed JWTs instead of client secrets (#166)

Fixed​

  • Admin token security — Production deployments now refuse to start without an explicit admin token; auto-generation and DEBUG logging restricted to development mode only (#118)
  • Right-to-erasure cascade — DeleteUser now deletes credentials, presentations, tenant memberships, WebAuthn challenges, invite references, and WebSocket sessions across all stores (#89)
  • VCI flow resumption — Auth code and code verifier now propagate correctly through flow state; credential issuer and selected configuration ID included in completion messages (#122)
  • VP response body decoding — JSON string responses from verifiers are now properly decoded (#126)
  • Proof JWT issuer claim — OID4VCI proof JWTs now include iss claim set to redirect URI (#133)
  • Trust cache isolation — Verifier trust evaluations use a dedicated in-memory TTL cache instead of polluting the persistent store (#130)
  • go-trust URL subject support — Bumped to v0.4.0 to enable subject_type="url" in AuthZEN resolver (#149)
  • SSRF vs TLS decoupling — AllowPrivateIPs and AllowHTTP now independent of InsecureSkipVerify, fixing metadata resolution in private networks with valid TLS (#152)
  • PDP client restrictions — Operator-configured PDP endpoints now use an unrestricted HTTP client, allowing internal/localhost addresses without disabling SSRF protection globally (#158)
  • RFC 8615 well-known URIs — Issuer metadata URLs now correctly constructed per RFC 8615 for issuers with path components (#164)
  • VP verifier encryption key extraction — Added x5c certificate chain fallback for mdoc thumbprint calculation when kid is absent (#161)
  • Encryption JWK algorithm — alg field now set on encryption JWK for credential_response_encryption (#122)

Changed​

  • VP credential selection flow — Consolidated two-step matching + consent into single credential_selection round-trip; client performs local matching and presents consent UI in one pass (#136)
  • GDPR log cleanup — Removed admin token, user IDs, holder DIDs, and subject IDs from INFO-level logs across all components (#89)
  • Default registry URL — Updated from .well-known/vctm-registry.json to /api/v1/schemas.json in default config (#141)
  • Issuer metadata resolution — Engine OID4VCI flow now uses shared issuermetadata.Resolver with SSRF protection and TTL caching (#134)

Security​

  • Admin token enforcement — Production mode now fails fast if no admin token is configured, preventing accidental deployments with auto-generated credentials (#118)
  • PII minimization — User identifiers removed from production logs to comply with GDPR Article 5(1)(c) data minimization (#89)
  • Signed metadata verification — Issuer metadata with signed_metadata JWT that fails verification now hard-fails instead of silently falling back to unsigned metadata (#151)
  • SSRF protection for issuer-controlled URIs — jwks_uri and logo fetching now block private/loopback/link-local IPs and cloud metadata endpoints when AllowPrivateIPs=false (#151)

[v0.4.1] - 2026-04-20​

Fixed​

  • Fixed proof validation logic to correctly handle attestation proofs that can cover multiple credentials, unlike JWT proofs which require one proof per credential instance. The validator now only enforces proof count requirements for JWT proofs and ensures all received proofs are of the same type (#117)

[v0.4.0] - 2026-04-20​

Added​

  • OIDC gate for identity binding (#47): Require users to authenticate with an external IdP before registration or login. Includes OIDCGateMiddleware for JWKS-based token validation, GET /api/v1/tenants/:id/config for frontend tenant configuration, configure-oidc-gate CLI command with --bind-identity flag, and IdentityBinding domain model for linking OIDC subjects to wallet accounts.
  • OID4VCI authorization code flow enhancements (#103): Comprehensive security improvements including PAR (RFC 9126) with automatic fallback, PKCE (RFC 7636) with conditional enablement, DPoP (RFC 9449) with nonce handling and retry logic, credential response encryption (OID4VCI §7.3) with algorithm negotiation, OAuth state parameter for CSRF protection, and structured OAuth error parsing. Scope handling now uses issuer metadata without hardcoded fallbacks.
  • Match request/response protocol (#78): Dedicated message types (match_request/match_response) for privacy-preserving client-side credential matching in OID4VP flows, following the sign_request/sign_response pattern with explicit message ID correlation, 30-second configurable timeout, and error reporting.
  • Trust integration tests (#83): Wire go-trust testserver into integration tests covering issuer/verifier trust evaluation, per-flow PDP configuration, AuthZEN wire protocol, session overrides, policy-based decisions, discovery, and health recovery scenarios.
  • TLS configuration for admin server (#96): Separate AdminTLS configuration option allows the admin HTTP server to use dedicated certificates independently of the main TLS config, addressing security needs when admin traffic flows over untrusted network segments. Backward compatible with fallback to shared TLS settings.
  • AuthZEN proxy endpoint (#72): Frontend trust evaluation via /v1/evaluate and /v1/resolve endpoints with per-tenant PDP configuration, configurable tenant lookup failure behavior, and SPOCP-based authorization rules. Includes unified mode support (#112).
  • Security startup warnings (#79): Log warnings at startup for potentially dangerous configurations (disabled trust evaluation, CORS wildcard) with elevated severity in production environments (detected via ENVIRONMENT, GO_ENV, or APP_ENV).
  • Client ID support for verifiers (#46): Verifiers can now specify client_id with validation for client_id_scheme, and configured client IDs are used as VP audience when set.
  • Support for different proof types in OID4VCI (#116): Engine now handles multiple proof type formats from issuers, properly formatting proofs before sending and validating only one type is present per request.

Fixed​

  • AuthZEN proxy routes missing in unified mode (#112): Routes /v1/evaluate and /v1/resolve now register correctly when running with -mode=backend,engine. Also fixed store resource leak in error path.
  • Query string privacy leak in registry logger (#114): Removed RawQuery from structured logs to prevent exposure of sensitive parameters like ?vct=, ?tenant=, and issuer URLs.
  • JWT compatibility (#77): Accept uuid claim in addition to sub for wallet-backend-server compatibility.
  • Admin token log exposure (#80): Reduced logging of sensitive admin token data.
  • Data races in requestProofs tests (#116): Resolved race conditions using channels for proper synchronization.
  • WebAuthn attestation configuration (#76): Made attestation format configurable with none as default, addressing BER signature failures with direct attestation.

Changed​

  • Go version (#90, #94): Upgraded to Go 1.26 with CI now reading version from go.mod instead of hardcoded values.
  • Certificate parsing (#46): Integrated go-cryptoutil for extensible certificate parsing, promoted to direct dependency.
  • WebSocket authentication format (#72): Support new auth format with tenantId field.
  • Deprecated field removal (#72): Removed deprecated TrustEndpoint field in favor of per-tenant PDP configuration.
  • Authorization rules loading (#72): Use go-spocp's native file loading for multi-line rules.
  • Logo validation (#76): Allow HTTP URLs in dev/test environments for easier local development.
  • Dependency updates: gin v1.11.0→v1.12.0, gin-contrib/cors v1.7.6→v1.7.7, go-webauthn/webauthn v0.16.3→v0.16.5, go-cryptoutil v0.2.0→v0.5.0, go-trust v0.0.0-20260223112607→v0.3.0, mongo-driver v1.17.6→v1.17.9, golang.org/x/crypto v0.49.0→v0.50.0, golang.org/x/time v0.14.0→v0.15.0 (#91, #111).

Security​

  • Error sanitization and WebSocket limits (#72): Hardened error handling to prevent information leakage and added WebSocket connection limits with thread safety improvements.
  • Security toolchain (#90): Integrated Trivy vulnerability scanning, gosec, and govulncheck into CI pipeline.
  • Production fail-closed guard (#112): AuthZEN proxy initialization now fails closed in production when rules file is invalid.

[v0.3.0] - 2026-03-26​

Added​

  • Attestation conveyance is now configurable, allowing operators to control whether authenticator attestation statements are requested during registration (#49)

Fixed​

  • Default attestation conveyance changed to "none" to avoid unnecessary privacy exposure and compatibility issues with authenticators that don't support attestation
  • BER-encoded ECDSA signatures from certain authenticators are now correctly parsed by switching to a patched webauthn library fork
  • Docker badge now correctly references the container registry workflow

Changed​

  • Documentation updated to reflect production-ready status
  • Dependency management simplified by using remote module replace directives instead of local paths

[v0.2.1] - 2026-03-25​

Fixed​

  • Upgraded go-webauthn to v0.16.1 to fix authentication failures with YubiKey 5.8 devices that produce BER-encoded ECDSA signatures instead of the expected IEEE P1363 format (#48)

[v0.2.0] - 2026-03-19​

Added​

  • Container images for wallet-admin are now built and published (#44)
  • X-Served-By response header identifies which server instance handled each request (#40)
  • require_invite configuration option for tenant sync to control invitation requirements (#39)
  • mTLS support for MongoDB connections, allowing mutual certificate authentication (#42)
  • TLS configuration for all HTTP listeners, enabling encrypted server communications (#41)
  • Centralized HTTP client for proxy and egress traffic with configurable TLS settings (#43)

Fixed​

  • Race condition in readiness test by switching to atomic.Int64 for thread-safe counter access

[v0.1.1-RC1] - 2026-04-30​

Added​

  • Build workflow automation for continuous integration

Changed​

  • Enhanced credential debugging by logging fully decoded credential data instead of partial information

[v0.1.1-RC0] - 2026-04-30​

Changed​

  • Allow multiple relying party origins to be configured, enabling a single verifier instance to serve multiple frontend applications or domains (#144)

[v0.1.0] - 2026-03-17​

Added​

  • /readyz endpoint with mode-specific readiness checks for better deployment health monitoring (#7a9ffcf4, #2bc09d31)
  • wallet-admin sync command for YAML-based tenant configuration management (#32612791)
  • JWK support for issuer and verifier trust evaluation, enabling cryptographic verification of trust relationships (#6bba0a3d)
  • Invite code system with admin mode controls, allowing tenant-level gating of new user registration (#242b6b78, #e34e1a95)
  • Support for specifying invite codes in POST requests and exposing require_invite flag in admin tenant API (#e3cfefbd, #2c6a033b)
  • client_id_scheme support in OID4VP with JWT signature verification for enhanced verifier authentication (#4e235846)
  • Verifier trust caching with domain model and storage layer for improved performance (#91eb9774)
  • Trust fields in verifier info responses to enable frontend trust indicators (#46889e6a)

Changed​

  • Extracted TrustService to pkg/trust with per-flow configuration for better modularity (#e54325d9)
  • Harmonized trust configuration with vc project for consistency across components (#8447d4ad)

Fixed​

  • High and medium severity trust evaluation gaps that could allow untrusted issuers or verifiers (#1f61ae57)
  • Invite system architectural hardening to prevent bypass and improve error handling (#6a4d51db, #e3cfefbd)
  • Provider lifecycle management by calling Start on providers implementing StartableProvider (#6d219a7b)
  • Registry configuration issues including envconfig tag cleanup (#5f04c86c, #ba0e1ce7)

Removed​

  • Deprecated tenant-scoped registration and login methods that were no longer in use (#34)
  • Unused tenant auto-retry login mechanism and tenant-mismatch error handling (#36)

[v0.1.0RC0] - 2026-03-03​

Added​

  • Multi-tenancy support with tenant discovery from passkey credentials, enabling a single deployment to serve multiple organizations (#27)
  • Header-based tenant routing via X-Tenant-ID instead of path-based routing, with tenant claims in JWT tokens for improved security (ADR-011)
  • Hybrid binary architecture with --mode flag supporting comma-separated roles (auth, storage, registry) to eliminate proxy requirements (#28)
  • WebSocket v2 engine protocol for real-time credential exchange with session store abstraction and Direct transport for frontend integration
  • Native SDK interfaces for CLI integration with key material extraction for trust evaluation
  • VCTM registry server with /issuer-metadata endpoint and image embedding to convert URLs to data URIs for offline use (#22)
  • Trust evaluation service with JIT discover-and-trust endpoint, mandating remote evaluation via AuthZEN PDP with per-tenant caching
  • TLS/mTLS configuration for HTTPS listeners and MongoDB connections, plus HTTP proxy support for egress requests
  • Secret loading from files for improved security in containerized deployments
  • Storage health check to /status endpoint with unified mode field across all operational modes
  • Admin API bearer token authentication with refresh-tokens capability in role-based access control

Fixed​

  • Tenant isolation vulnerabilities: userHandle validation in login, tenant-scoped user queries, and correct TenantID storage in credentials during registration (#17)
  • MongoDB and GORM index definitions to use correct fields (Verifier.URL) and ensure tenant_id presence in collections (#32, #33)
  • Race condition in 304 handler and deadlock when ConcurrentFetches=0 in registry fetcher
  • Passkey UUID generation, account deletion, and tenant-scoped route handling (#12, #13, #14)
  • HTTP proxy method handling to force uppercase and trim whitespace (#10)
  • Docker container /app/data directory ownership for nonroot user compatibility
  • Default tenant display name now returned in login-finish response and defaults to tenant name when not provided (#28)
  • SQLite storage selection now shows clear error message instead of generic failure
  • Verifier existence check returns appropriate error instead of 500 server error
  • Admin API routes now properly registered in provider architecture with session management

Changed​

  • Simplified trust architecture to use go-trust exclusively, removing redundant trust store layer
  • Unified HTTP server architecture with RouteProvider pattern across auth, storage, and registry modes
  • Registration and login APIs now use single global endpoints that complete operations for any tenant
  • Access logs no longer include /status and /health endpoints to reduce noise
  • Trust refresh interval moved from per-issuer to global server setting
  • Upgraded golangci-lint to v2.10.0 for configuration compatibility

Security​

  • Enforced tenant isolation through userHandle validation preventing cross-tenant credential access
  • Added JWT-based tenant security with tenant_id claims for authorization
  • Minimized user tracking and fingerprinting in authentication flows
  • Mandated remote trust evaluation via AuthZEN PDP instead of local trust decisions