Skip to content

fix(verifier): restore the unsigned "urlEncoded" request mode - #118

Open
Mortega5 wants to merge 10 commits into
mainfrom
fix/urlencode-mode
Open

fix(verifier): restore the unsigned "urlEncoded" request mode#118
Mortega5 wants to merge 10 commits into
mainfrom
fix/urlencode-mode

Conversation

@Mortega5

Copy link
Copy Markdown
Collaborator

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.

@Mortega5
Mortega5 requested review from vramperez and wistefan August 28, 2026 10:24
@Mortega5 Mortega5 added the patch Should be applied for dependency updates and small bugfixes. label Aug 28, 2026
Comment thread config/config.go Outdated

@vramperez vramperez left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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.

Comment thread verifier/verifier.go Outdated
// (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 == "" {

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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.

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed by e2ddbe9 — only default to byReference when it's actually in supportedModes, otherwise fall back to the first supported mode.

Comment thread verifier/verifier.go Outdated
values := url.Values{}
values.Set("response_type", "vp_token")
values.Set("response_mode", "direct_post")
values.Set("client_id", v.clientIdentification.Id)

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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.

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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.

Comment thread verifier/verifier.go
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)

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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.

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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.

Comment thread verifier/verifier.go
return request, err
}
if dcql != nil {
dcqlJSON, err := json.Marshal(dcql)

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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.

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed by c9399ca — added omitempty to both DCQL.CredentialSets and CredentialQuery.TrustedAuthorities.

Comment thread README.md Outdated
# 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.

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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".

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed by da02c00 — reworded to "redirect_uri only works with the urlEncoded request mode".

@Mortega5
Mortega5 force-pushed the fix/urlencode-mode branch from f993434 to 4347b98 Compare August 30, 2026 18:28
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.
@Mortega5
Mortega5 force-pushed the fix/urlencode-mode branch from 4347b98 to 979fe7b Compare August 30, 2026 18:29
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

patch Should be applied for dependency updates and small bugfixes.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants