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_metadatafrom OID4VCI responses, both at the response level (OID4VCI 1.1) and per-credential, preserving extra members verbatim for downstream consumers (#463) - Engine requires
notification_idwhencredential_metadatacontains a secret seed, ensuring proper tracking of seed delivery (#463) - Engine enforces encrypted response delivery when advertising
secret_seedcapability, preventing accidental plaintext seed transmission (#463)
Fixed
- Type assertions throughout codebase are now checked for safety, enabled via errcheck's
check-type-assertionslinter option (#459) - Engine serves valid
secret_seedadvertisements 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,
AuthMiddlewarehardcoded a nil blacklist, and the/user/session/logoutroute 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,
evaluateVerifierTrustcalls 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.
evaluateTrustinoid4vci.gono longer downgrades to frontend-mediated trust when a configured issuer PDP errors. Plain-JSON issuer metadata'scredential_issuerclaim 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 enforceX-Tenant-IDviaTenantHeaderMiddlewareand honoroidc_gateconfiguration. Registration enforcesbind_identityup front; login re-validates audience and required claims against the credential's real tenant.FinishRegistrationrejects 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
issuermatches the requested issuer, uses PKCE (S256) end-to-end, requireshttps://issuer URLs (unlesshttp_client.allow_httpis set), and binds thestateparameter to a signedHttpOnly/SameSite=Laxcookie to prevent login CSRF. Theadminclaim (groups/roles containing "admin") only mints elevated permissions whenoidc_gate.trust_admin_claim: trueis explicitly set. BothLoginandCallbacknow 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: trueandrequest_jwtcorrectly.x509_san_urirequest-object verification now runs before the metadata fetch.x509_san_dns/x509_san_uri/x509_hashnow send the properly prefixedclient_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.
DeleteUsernow 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.
FinishRegistrationnow 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.FinishWebAuthnRegistrationnow 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.FinishWebAuthnLoginnow populatesOIDCGateBinding.AudienceandOIDCGateBinding.Claims, soFinishLoginre-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.Audiencesand 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 newhttp_client.trusted_idp_hostsallowlist 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_eventsconfig (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 inHandshakeCompleteMessage.config.ping_interval_ms. (#367) - Verifier trust cache can be disabled.
trust.cache_disabledandtrust.cache_ttl_secondsallow 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/refreshis 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'sconsentresponse fits within the DCQL query sent. Inenforcemode, violations block presentation and returnaccess_deniedto the verifier. (#428, #140 part A) - Registry role reintegrated. The registry can now run as a role within the combined binary (
--role registryorWALLET_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 deprecatedprefer_signedboolean andmetadata_fallback_on_4xxflag. Retries the other media type only on HTTP 406 unlessanyis 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-claimsaccepts JSON orkey=valuepairs. (#421, #51 / #52 / #55) - Validator cache now bounded.
ValidatorCacheevicts 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 explicitsession_idfield, matching"Session established", so rapid reconnects can be distinguished from server-side bugs. (#293)
Fixed
- Holder DID resolution unified.
getHolderDIDnow consistently prefersuser_idover the legacydidclaim (AS-issued tokens carry onlysub/user_id). (#391, #384 W-5 INFO) - Issuer metadata tolerates malformed credential configurations.
credential_configurations_supportedis now decoded one entry at a time; one undecodable configuration is skipped with a warning instead of failing the whole document. The legacy top-levelclaimsfield (when an array) no longer breaks decoding. (#417, #370) - Dependency updates. Bumped
github.com/gin-contrib/corsto 1.7.9 (Trivy security findings) andgithub.com/go-webauthn/webauthnto 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 deprecatedUserService.Login()are gone.hasPasswordno longer appears in account info responses. Existingpassword_hashvalues in MongoDB are ignored on read and dropped on the next write. (#420, #162) - Verifier
credential_typescontext preserved.pkg/trustnow sendscredential_typesto 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_idsfrom the authorization request is now preserved in/v1/evaluateand/v1/resolvecalls 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
admingroup/role claim to auto-mint elevated permissions must now explicitly setoidc_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://unlesshttp_client.allow_httpis set. Existinghttp://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 whoseX-Forwarded-Foris 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 rotateX-Forwarded-Forto dodge the per-IP bucket. (#425, #65) - BREAKING: AS audiences now required.
as.audiencesmust be set when the AS is enabled. Legacy HMAC tokens requireserver.rp_idin the audience list. (#414, go-tokenauth v0.5.0) - BREAKING: Registry tokens validated against explicit audiences. The registry now requires
as.audienceswhen auth is enabled, following go-tokenauth v0.5.0. (#431) - API:
hasPasswordremoved 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-Challengeresponse header or by POSTing the AS'schallenge_endpoint), and retries the request with the challenge embedded in the PoP'schallengeclaim. (#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
audclaim matches the credential endpoint. (#366) - Fixed trust evaluation for verifiers identified by DIDs. The query firewall now permits
kidas a resource type, allowing verifiers that sign requests with akidreferencing 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-injectionexclusion now works correctly usingquery-filtersinstead of the previously-inertpaths-ignoreconfiguration. 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-trustfrom v0.20.6 to v0.21.1, adding support for did:jwk resolution, local DID registry configuration (did:key, did:jwk), and acceptingkidas 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-certendpoint 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_idshorter 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/v2andgithub.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_detailsfromflow_startto the Authorization Request alongsidescope, and honours thecredential_identifierechoed 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/detailreturns non-PII user information including passkeys, DID, and wallet type. A stub tenant statistics endpoint atGET /admin/tenants/:id/statsreturns 501. (#250) -
Audit events for invite lifecycle. The admin API now emits
invite:created,invite:updated(withrenew/revokeaction), andinvite:deletedevents 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_CREDENTIALSflow error carrying the requested credential types as data, so it can phrase the explanation in the user's own language. The verifier receivesaccess_deniedwith the sameerror_descriptiona 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, orinsecure_skip_verifyare 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 thex5cheader 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 withkid-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 acceptsdecentralized_identifier(the final specification's name for the DID scheme) alongside the draft spellingdid, 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:createdaudit events now use the verifier URL as subject (matchingissuer:created), withverifier_idandnamein 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 tomongodbwhen 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 existserrors. (#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/cors1.7.7→1.7.8,github.com/go-webauthn/webauthn0.18.0→0.18.1,github.com/sirosfoundation/go-trust0.20.5→0.20.6,golang.org/x/crypto0.56.0→0.57.0,golang.org/x/sync0.22.0→0.23.0,golang.org/x/time0.15.0→0.16.0,github.com/go-jose/go-jose/v44.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_authaction 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 ensurescnf == DPoP keybecause 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 withdpop_jwkskip the probe and use legacy mode. (#318)
Changed
- Renewal flow: in client-held mode
flow_completereturnsdpop_key_idinstead of the privatedpop_jwk, and a renewalflow_startsendsdpop_key_idback so the engine asks the client to sign with the key the refresh token is bound to.dpop_jwkkeeps 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
algheader specified in the verifier's JWK instead of always inferring it from the key material, preventing validation failures when the verifier checks the returnedvp_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
VerifyAttestationcall 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 allnow starts every role. It expanded to a hardcoded list of five, silently omittingstorageandwallet-provider, so a deployment that asked for every role was not running those two; it now expands toValidRoles. The-modehelp 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/resolveendpoint 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 anissuer_entitlementdecision alongside metadata. Controlled byISSUER_ENTITLEMENT_MODEenvironment variable (warnby default,fail, oroff). The defaultwarnmode 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_authenticationorcertificationat all when the client omittedsecurity_properties, and could still dropuser_authenticationfor 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_hashare 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 arequest_urifetch 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 mirrormdoc-issuer-auth, causing all VICAL issuer-trust queries to be denied before reaching the policy decision point regardless of issuer identity (#296) - Fixed
--mode registrypanicking on startup when CORS origins list is empty. Now handles empty configuration gracefully and warns when wildcard CORS is combined withAllowCredentials(#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_httpis enabled (#282). Previously, resolving a plain-HTTP credential issuer (subject_type: "url") failed even withallow_httpconfigured — the scheme validation inResolve()hardcoded HTTPS regardless of the flag, and the authorization rules lacked an HTTP variant forcredential_issuerqueries. Both layers now honor theallow_httpsetting. 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
/authorizerequest 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). TheprocessTS11Responselogic for fetching and paginating/api/v1/schemas.jsonnow uses the sharedgithub.com/sirosfoundation/go-ts11clientlibrary 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-authaction is now permitted in the default SPOCP authorization policy, enabling SDK reader-trust checks (subject typekey, resource typex5c) to pass through/v1/evaluatewithout requiring a custom rules file (#279)
Fixed
- Resolved
crypto/ecdsadeprecation warnings (Go 1.26+) by migrating from direct field access (PublicKey.X/Y,PrivateKey.D) to the newECDH()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_presentationto enable correct ZKverifier_contextderivation 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_tokenfrom 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.jwtresponses changed fromA128CBC-HS256toA128GCMwhen verifiers don't declareauthorization_encrypted_response_encin 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
tacclaim. Routes now require specific TAC values:r(read),w(write/mutate),l(list),i(create), ord(delete). WebSocket flows enforcerfor OID4VP presentation andifor 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 onlyopenid4vp://and the drafthaip://were accepted, causing real verifier requests to fail with "invalid message format" instead of dereferencing the request. (#270)
Security
- Upgraded
go-tokenauthto 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/v99.21.0 → 9.22.0 andkin-openapipatch bump. (#271)
[v0.10.1] - 2026-08-06
Fixed
- Key Attestation nonce compatibility: The
attestationproof type now sends bothc_nonceandnonceclaims to the credential endpoint, fixing issuance failures with providers (like geneva2026.mdoc.online) that expectnoncerather than the TS03-specifiedc_nonce. An unrecognized extra claim is harmless to conformant verifiers. (#265)
Changed
- SPOCP delegation policy documentation: Replaced misleading read-only rules in
delegation.ruleswith 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=authdeployments, 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.modesetting (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.jsonroute 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-backendaudiences and rejected on identity-bearing routes. AuthZEN proxy and engine transport routes require one of those audiences; general user-facing routes requirewallet-backend. (#262)
Fixed
- Authorization Server metadata unreachable via AuthZEN proxy: The
/v1/resolveendpoint's allowlist rejectedresource_type=oauth-authorization-serverqueries before reaching the handler that explicitly supported them, breaking PAR-endpoint discovery for wallets. The allowlist now includesoauth-authorization-server. (#260) - SPOCP wildcard rules never matched: Rules loaded from
.rulesfiles 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=authalone would panic at startup because the AS'sEnableForRole()call expected a config that was only loaded for other roles.RoleAuthis now included in the config-load condition. (#259) - Missing JWKS route in standalone wallet-provider mode: Deployments running
--mode=wallet-provideras 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_statusclaims (no revocation-chaining support); WIA lifetime now defaults to 5 minutes. Fixed the Key Attestation's nonce claim (c_nonce) and removed its strayissclaim. Corrected theattestation_sourceclaim'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 bymode: ietf) is rejected if nowia.issueris set, preventing silent misuse ofwallet_provider_urias 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, anduser_authenticationclaims inkeyattestation+jwtare now clamped to software-level defaults (iso_18045_basic/"none") unless the request'swallet_instance_idresolves 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/challengeand/wallet-provider/wia/generateendpoints issue single-use, PoP-bound WIA JWTs signed with the wallet-provider key and including x5c chains,cnfbinding 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-vplinks with no query string) instead of treating them as empty by-value requests. (#255) - WIA issuance now rejects suspended or revoked wallet instances; previously
Upsertunconditionally reset status toActive, 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.UserIDis now populated during WIA issuance, fixing the previously-empty results fromGET /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
*_pathfile-based loading, consistent with other secrets in the configuration. (#221)
[v0.8.0] - 2026-07-28
Added
- Registry support for
mso_mdoccredentials alongside sd-jwt VCTM: local overrides, dynamic fetch, and TS11/registry polling now recognizedoctype-identified MDDL documents in addition tovct-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_schemesupport: 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: readby 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.jwtresponse mode (#235) — Whenresponse_mode=direct_post.jwtis used butauthorization_encrypted_response_algis absent fromclient_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_serversarray 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-revalidateheaders 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, andcertificationclaims 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_dataarray 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
ExternalURLinstead of theHostheader 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_issueridentifier per RFC 8615 (#214)
[v0.6.0] - 2026-06-10
Added
- Resource-type routing for
/v1/resolveendpoint:oauth-authorization-servernow resolves AS metadata via RFC 8414 well-known discovery, andcredential_offer_urifetches and validates OID4VCI credential offers server-side (#170, #153) - Forward optional
credential_typesarray through/v1/resolveto upstream PDP asaction.parameters.credential_typesfor credential-type-specific trust evaluation (#198) - Configuration reference generator (
make gen-config-docs) that producesdocs/CONFIGURATION.mdfrom 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
modeconfig field (ts11orregistry) to select between legacy and new formats (#174) - Support for
did:webcredential issuers:subject_type=keywithresource_type=credential_issuernow converts DID to URL and resolves issuer metadata (#206, #208)
Fixed
- DPoP JTI reuse on token endpoint
use_dpop_nonceretry: each retry now generates a freshclient_assertionJWT 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, verifierclient_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-allwith 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
integrationbuild tag sogo test ./...runs only fast unit tests (#174) - Upgraded OpenAPI spec from 3.0.0 to 3.1.0 for
if/thenschema 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
JWTConfigonly supported inlinejwt.secret, causingJWT secret is emptyerrors when deployments usedjwt.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) andexp(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
WriteTimeoutimmediately 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-Byheader 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-Byheader now appears on WebSocket upgrade responses. Gin middleware cannot inject headers aftergorilla/websockethijacks 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.modand Dockerfiles for reproducible builds. (#180)
[v0.5.1] - 2026-05-15
Fixed
- Fixed
private_key_jwtclient authentication to include thekidheader in JWT assertions and use the correctaudclaim 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
formatandvctparameters 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/healthzendpoint 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/metadatafetches 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_originsconfig field enables native app wrappers (Android/iOS) to register alongside web frontends (#144) - URL-based issuer resolution —
/v1/resolveendpoint 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.jsonto/api/v1/schemas.jsonwith 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_jwtclient 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 —
DeleteUsernow 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
issclaim 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 —
AllowPrivateIPsandAllowHTTPnow independent ofInsecureSkipVerify, 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
kidis absent (#161) - Encryption JWK algorithm —
algfield now set on encryption JWK forcredential_response_encryption(#122)
Changed
- VP credential selection flow — Consolidated two-step matching + consent into single
credential_selectionround-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.jsonto/api/v1/schemas.jsonin default config (#141) - Issuer metadata resolution — Engine OID4VCI flow now uses shared
issuermetadata.Resolverwith 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_metadataJWT that fails verification now hard-fails instead of silently falling back to unsigned metadata (#151) - SSRF protection for issuer-controlled URIs —
jwks_uriand logo fetching now block private/loopback/link-local IPs and cloud metadata endpoints whenAllowPrivateIPs=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
OIDCGateMiddlewarefor JWKS-based token validation,GET /api/v1/tenants/:id/configfor frontend tenant configuration,configure-oidc-gateCLI command with--bind-identityflag, andIdentityBindingdomain 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 thesign_request/sign_responsepattern 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
AdminTLSconfiguration 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/evaluateand/v1/resolveendpoints 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, orAPP_ENV). - Client ID support for verifiers (#46): Verifiers can now specify
client_idwith validation forclient_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/evaluateand/v1/resolvenow 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
RawQueryfrom structured logs to prevent exposure of sensitive parameters like?vct=,?tenant=, and issuer URLs. - JWT compatibility (#77): Accept
uuidclaim in addition tosubfor 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
noneas 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.modinstead of hardcoded values. - Certificate parsing (#46): Integrated
go-cryptoutilfor extensible certificate parsing, promoted to direct dependency. - WebSocket authentication format (#72): Support new auth format with
tenantIdfield. - Deprecated field removal (#72): Removed deprecated
TrustEndpointfield 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-Byresponse header identifies which server instance handled each request (#40)require_inviteconfiguration 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
/readyzendpoint with mode-specific readiness checks for better deployment health monitoring (#7a9ffcf4, #2bc09d31)wallet-admin synccommand 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_inviteflag in admin tenant API (#e3cfefbd, #2c6a033b) client_id_schemesupport 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
TrustServicetopkg/trustwith 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
Starton providers implementingStartableProvider(#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-IDinstead of path-based routing, with tenant claims in JWT tokens for improved security (ADR-011) - Hybrid binary architecture with
--modeflag 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-metadataendpoint 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
/statusendpoint 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/datadirectory 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
/statusand/healthendpoints 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