fix: use @sirosfoundation/dc-api v0.5.0's authorization-request bridge - #534
Conversation
Bumps the vendored dc-api.js bundle to v0.5.0 and wires the verifier's native DC API path through the new requestCredentialFromAuthorizationRequestURI helper instead of passing the redirect-flow authorization_request URI directly as the DC API request value - that URI is neither a valid JWT (openid4vp-v1-signed) nor a valid raw-params object (openid4vp-v1-unsigned), so no protocol handler could ever parse it and every native DC API attempt failed. The new helper resolves the authorization request into whatever shape the detected protocol actually needs. Also fixes two bugs found in the same testing pass, both required for the above to actually reach a working state: - supported_wallets can arrive as JSON null (an unconfigured Go map marshals that way) - the schema had no fallback for it, so the whole /ui/metadata response failed to parse and the page hung on its loading spinner before a user could ever select a credential. - The claim-selection form always built DCQL meta.vct_values, even for mso_mdoc credentials, which have no vct - the correct constraint there is meta.doctype_value (OpenID4VP 1.0 6.4.1). Sending vct_values for an mdoc credential matches nothing on the wallet side. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01NhWrEC7D4b3vxZ4wm3gDML (cherry picked from commit 30c3e69)
There was a problem hiding this comment.
Pull request overview
This PR fixes verifier-side W3C Digital Credentials API (DC API) integration issues discovered during Android end-to-end testing, improving native DC API request handling and DCQL query construction so wallet interactions succeed in real devices and edge configurations.
Changes:
- Routes native DC API requests through
requestCredentialFromAuthorizationRequestURI()to turn anopenid4vp://...authorization request URI into the protocol-specificdatashape expected bynavigator.credentials.get(). - Makes
/ui/metadataparsing resilient whensupported_walletsisnull(e.g., no wallets configured). - Fixes mdoc (
mso_mdoc) DCQL meta constraint generation to usemeta.doctype_valueinstead ofmeta.vct_values.
Reviewed changes
Copilot reviewed 3 out of 3 changed files in this pull request and generated 1 comment.
| File | Description |
|---|---|
| internal/verifier/staticembed/presentation-definition.js | Adjusts metadata parsing defaults and corrects DCQL meta construction for mso_mdoc in the claim-selection flow; switches native request path to the new bridge helper. |
| internal/verifier/staticembed/dc-api.js | Updates vendored dc-api bundle with helpers to resolve authorization request URIs into protocol-specific request data for native DC API calls. |
| internal/verifier/staticembed/dc-api-polyfill.js | Re-exports the new authorization-request bridge function from the dc-api package for use by the verifier UI. |
Suppressed comments (1)
internal/verifier/staticembed/dc-api.js:141
- requestCredentialFromAuthorizationRequestURI() currently calls buildRequestData() without passing options.signal, so even if buildRequestData supports cancellation the fetch path can’t use the AbortController from the caller.
async function requestCredentialFromAuthorizationRequestURI(authorizationRequestUri, options) {
const protocol = getBestProtocol(options?.protocolPreference);
if (!protocol) return null;
const data = await buildRequestData(protocol, authorizationRequestUri, { fetchFn: options?.fetchFn });
return requestCredential(protocol, data, options);
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
requestCredentialFromAuthorizationRequestURI's caller
(_tryNativeDCAPI in presentation-definition.js) creates an
AbortController and passes its signal specifically so the native DC
API attempt can be cancelled if the user picks another flow or
navigates away. The signal was silently dropped before it could do
anything:
- requestCredentialFromAuthorizationRequestURI forwarded only
{ fetchFn } to buildRequestData, not signal.
- buildRequestData never read options.signal in the first place.
- _fetchJwt's fetchImpl(requestUri) call had no way to pass a signal
even if one had reached it.
A slow/hung request_uri fetch could therefore never be aborted, and
the UI would appear stuck even after the user cancelled.
Patched directly in the vendored bundle (internal/verifier/staticembed/
dc-api.js) rather than only in the @sirosfoundation/dc-api source,
since that's what's actually shipped by this PR; the same fix should
be upstreamed to dc-api separately so the next version bump doesn't
reintroduce it.
No JS test harness exists for internal/verifier/staticembed/ (make
test-js only covers internal/apigw/staticembed/tests/*.test.js), so
verified this by tracing the full call chain by hand rather than
adding new test infrastructure for this fix alone.
|
Fixed the AbortController.signal issue Copilot flagged (commit 6c9280d) — it's actually a real, live bug: `_tryNativeDCAPI` (presentation-definition.js) creates an `AbortController` specifically so a native DC API attempt can be cancelled, and passes `{ signal: abortController.signal }` into `requestCredentialFromAuthorizationRequestURI` expecting it to work. The signal was silently dropped at all three points along the chain:
So a slow/hung `request_uri` fetch could never actually be aborted — the UI would appear stuck even after cancelling. Threaded `signal` through all three. Patched directly in the vendored bundle since that's what's actually shipped here; flagging that the same fix should go upstream to `@sirosfoundation/dc-api` too so the next version bump doesn't reintroduce it. No JS test harness exists for `internal/verifier/staticembed/` (`make test-js` only covers `internal/apigw/staticembed/tests/`), so I verified this by tracing the full call chain by hand rather than standing up new test infrastructure for one fix. Go build, vet, and |
|
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 3 out of 3 changed files in this pull request and generated no new comments.
Suppressed comments (2)
internal/verifier/staticembed/presentation-definition.js:511
- The comment examples use
openid4vp://...?but the verifier constructs authorization requests as an opaque URI (openid4vp:cb?...) (see pkg/openid4vp/context.go). Using the wrong shape in comments is misleading when debugging URL parsing behavior across browsers/wallets; consider updating the example to match the actual URI format (or use the more generalopenid4vp:form).
* The authorization_request URI is the same openid4vp://...?client_id=...
* &request_uri=... deep link used for QR/redirect - NOT itself a valid DC
internal/verifier/staticembed/presentation-definition.js:437
- This block says “mso_mdoc credentials have no vct” but then reads
this.credentialAttributes.vctfor the doctype. Since the UI schema requires avctstring for all formats, it would be clearer to state that this field carries the VCT for SD-JWT credentials and the ISO doctype for mso_mdoc credentials, to avoid confusion for future maintainers.
// mso_mdoc credentials have no vct - the DCQL equivalent constraint
// is doctype_value (OpenID4VP 1.0 6.4.1), not vct_values. Sending
// vct_values for an mdoc credential matches nothing on the wallet
// side (no mdoc credential has a vct), so the request always comes
// back empty.
const meta = this.credentialAttributes.format === "mso_mdoc"
? { doctype_value: this.credentialAttributes.vct }
: { vct_values: [this.credentialAttributes.vct] };



Summary
Follow-up to #504 (the DC API polyfill integration, merged 2026-07-29). Live end-to-end testing against a real Android device (Chrome DC API + native mdoc credential presentation) surfaced a real bug in the native DC API path introduced there, plus two related bugs found in the same testing pass.
Bugs fixed
authorization_requestURI (openid4vp://...?client_id=...&request_uri=...) directly as the DC APIrequestvalue. That URI is neither a valid JWT (openid4vp-v1-signedneeds one) nor a valid raw-params object (openid4vp-v1-unsignedneeds that instead) - no protocol handler could parse it, so every native DC API attempt failed silently ("Your info wasn't found"). Fixed by bumping the vendored@sirosfoundation/dc-apibundle to v0.5.0 and wiring the native path through its newrequestCredentialFromAuthorizationRequestURI()helper, which resolves a standard authorization request URI into whateverdatashape the detected protocol actually needs (fetchingrequest_urifor the JWT when required)./ui/metadatafailed to parse when no wallets are configured:supported_walletscan arrive as JSONnull(an unconfigured Go map marshals that way) - the schema had no fallback for it, so the whole response failed to parse and the page hung on its loading spinner before a user could ever select a credential.meta.vct_values, even formso_mdoccredentials, which have novct- the correct constraint there ismeta.doctype_value(OpenID4VP 1.0 §6.4.1). Sendingvct_valuesfor an mdoc credential matches nothing on the wallet side.Test plan
go build ./...- clean.make test-js- 49/49 passing.Co-Authored-By: Claude Sonnet 5 noreply@anthropic.com