fix(verifier): restore the unsigned "urlEncoded" request mode - #118
fix(verifier): restore the unsigned "urlEncoded" request mode#118Mortega5 wants to merge 10 commits into
Conversation
vramperez
left a comment
There was a problem hiding this comment.
Nice catch on the missing urlEncoded branch. A few things I would fix before merging — mainly the new defaultRequestMode default breaking urlEncoded-only deployments at startup, and the fact that urlEncoded still has no validation for the clientIdentification it now depends on.
| // (via gookit/config); callers building configModel.Verifier directly (tests, or any | ||
| // future caller) get the zero value. Fall back here so behaviour matches the documented | ||
| // default regardless of how the config was constructed. | ||
| if verifierConfig.DefaultRequestMode == "" { |
There was a problem hiding this comment.
This makes the shipped defaults self-contradictory: SupportedModes defaults to ["urlEncoded"] (config.go:166) while DefaultRequestMode defaults to byReference, so any config that sets neither now dies at startup with logger.Fatalf — including the vcverifier helm chart's own default values (supportedModes: ["urlEncoded"]) and the DSC demo deployments, i.e. exactly the urlEncoded-only setups this PR targets, in a PR labelled patch. Please only fall back to byReference when it is actually in SupportedModes and otherwise use SupportedModes[0], so a previously valid config keeps booting and startup only fails on an explicitly wrong defaultRequestMode.
There was a problem hiding this comment.
Fixed by e2ddbe9 — only default to byReference when it's actually in supportedModes, otherwise fall back to the first supported mode.
| values := url.Values{} | ||
| values.Set("response_type", "vp_token") | ||
| values.Set("response_mode", "direct_post") | ||
| values.Set("client_id", v.clientIdentification.Id) |
There was a problem hiding this comment.
clientIdentification.id is never validated for this mode — the key check at verifier.go:404 only runs for byValue/byReference, and the helm chart ships clientIdentification.id: null together with supportedModes: ["urlEncoded"], so the default path emits client_id= empty and the wallet rejects the request with an opaque error. Please reject an empty ClientIdentification.Id in verifyConfig when urlEncoded is in SupportedModes, so this fails loudly at startup instead of at scan time.
There was a problem hiding this comment.
Fixed by f726397 — when clientIdentification.id is left empty, it's now defaulted per-request to redirect_uri: + the actual response_uri, so it's always consistent instead of ever going out empty.
| values.Set("response_type", "vp_token") | ||
| values.Set("response_mode", "direct_post") | ||
| values.Set("client_id", v.clientIdentification.Id) | ||
| values.Set("response_uri", response_uri) |
There was a problem hiding this comment.
For the redirect_uri prefix the wallet's only trust check is that response_uri equals the URI embedded in client_id, but here client_id is static config while response_uri is derived per-request from c.Request.Host + pathPrefix — a second ingress hostname, an internal Service DNS name or a pathPrefix change silently desyncs them and every wallet rejects the request. Either derive client_id from response_uri when the id starts with redirect_uri:, or compare the two here and return an explicit error.
There was a problem hiding this comment.
Fixed by 9def3e0 — when clientIdentification.id is explicitly set with the redirect_uri: scheme, the host is now validated against the request's response_uri and rejected with an explicit error on mismatch, instead of silently sending a pair the wallet will reject.
| return request, err | ||
| } | ||
| if dcql != nil { | ||
| dcqlJSON, err := json.Marshal(dcql) |
There was a problem hiding this comment.
DCQL.CredentialSets and CredentialQuery.TrustedAuthorities have no omitempty (config/configClient.go:521 and :541), so this marshals "credential_sets":null into the query parameter — which is the confirmed parse blocker in eudi-lib-ios-siop-openid4vp-swift 0.33.0 (.exists() is true for an explicit null, .rawData() then throws "JSON is invalid.") and makes Lissi/EUDI fail on request resolution. Since those are precisely the wallets this unsigned mode is meant to unblock, worth adding omitempty to both fields (or a MarshalJSON on DCQL like the one CredentialQuery already has) in this PR.
There was a problem hiding this comment.
Fixed by c9399ca — added omitempty to both DCQL.CredentialSets and CredentialQuery.TrustedAuthorities.
| # identification of the verifier in communication with wallets | ||
| clientIdentification: | ||
| # identification used by the verifier when requesting authorization. Can be a did, but also methods like x509_san_dns | ||
| # identification used by the verifier when requesting authorization, following the OIDC4VP client identifier prefixes(see https://openid.net/specs/openid-4-verifiable-presentations-1_0.html). Can be a did (e.g. "did:web:..."), an x509_san_dns entry ("x509_san_dns:<hostname>") or a redirect_uri entry ("redirect_uri:<the verifier's own callback url>"). Only redirect_uri works with the "urlEncoded" request mode, see "Request modes" below - it is the only scheme whose requests must NOT be signed. |
There was a problem hiding this comment.
This reads as "urlEncoded only works with redirect_uri", which is the converse of the (correct) statement further down at line 571 — the code puts whatever clientIdentification.id holds into client_id regardless of mode, and the previous README example was client_id=did:key:verifier in urlEncoded. As phrased it tells existing urlEncoded + did: deployments they are misconfigured; suggest rewording to "redirect_uri only works with the urlEncoded request mode".
There was a problem hiding this comment.
Fixed by da02c00 — reworded to "redirect_uri only works with the urlEncoded request mode".
f993434 to
4347b98
Compare
The "urlEncoded" request mode was left undefined by a past refactor (generateAuthenticationRequest only handled byValue/byReference), even though it was still the documented default and listed in supportedModes, so requesting it failed with unsupported_request_mode. It is also the only mode compatible with the "redirect_uri" client identifier scheme, which per OIDC4VP must not be signed. Restore it, and document what clientIdentification needs (and does not need) for that scheme.
Add verifier.defaultRequestMode, defaulting to "byReference" so existing deployments keep their current behavior unchanged. Startup validation now rejects a default that isn't itself listed in supportedModes, instead of failing later on a live request.
…ference Only default the request mode to byReference when it is actually in supportedModes; otherwise use the first supported mode. Previously a supportedModes-only config (e.g. ["urlEncoded"]) with no explicit requestMode failed to start.
…configured Previously an unset clientIdentification.id produced an empty client_id for the "redirect_uri" scheme. Default it, per request, to the same response_uri it will be sent alongside, so the two are always consistent without needing explicit configuration.
…doesn't match response_uri A static clientIdentification.id can silently drift from the per-request response_uri (different ingress hostname, internal service DNS, a pathPrefix change), producing a client_id/response_uri pair every wallet rejects. Validate the host match at request time and fail loudly instead.
…from JSON Both fields lacked omitempty, so an unconfigured DCQL query serialized them as explicit JSON null. eudi-lib-ios-siop-openid4vp-swift 0.33.0 (used by Lissi/EUDI wallets) treats an explicit null as present but fails to parse it, breaking request resolution for those wallets.
…requestMode fallback Reword the clientIdentification.id note (redirect_uri only works with urlEncoded, not the reverse) and update the requestMode/urlEncoded docs to match the new default-derivation, host-validation and supportedModes-fallback behaviour.
4347b98 to
979fe7b
Compare
The "urlEncoded" request mode was left undefined by a past refactor
(generateAuthenticationRequest only handled byValue/byReference), even
though it was still the documented default and listed in supportedModes,
so requesting it failed with unsupported_request_mode. It is also the
only mode compatible with the "redirect_uri" client identifier scheme,
which per OIDC4VP must not be signed. Restore it, and document what
clientIdentification needs (and does not need) for that scheme.