Skip to content

Add Consumer API OpenID4VP verifier site - #1536

Open
tnotheis wants to merge 25 commits into
mainfrom
feat/openid4vp-verifier-site
Open

Add Consumer API OpenID4VP verifier site#1536
tnotheis wants to merge 25 commits into
mainfrom
feat/openid4vp-verifier-site

Conversation

@tnotheis

@tnotheis tnotheis commented Sep 3, 2026

Copy link
Copy Markdown
Member

Summary

  • extend the existing Consumer API /r/{referenceId} onboarding page with an embedded mobile-first OpenID4VP verifier
  • render the verifier markup in AppOnboarding.cshtml; the TypeScript bundle now only controls existing DOM nodes and performs browser-only loading, decryption, validation, and state updates
  • parse the NMSHD reference hash, fetch Token/RelationshipTemplate content, decrypt XCHACHA20_POLY1305 token content with @nmshd/crypto, and fall back to the previous onboarding flow when the content is not a VP token
  • validate TokenContentVerifiablePresentation.value with the existing Credo-based verifier and render loading/valid/invalid/closed states without a mock app/phone shell
  • extract displayed credential values from the Verifiable Presentation only; missing values are omitted instead of being replaced with sample/default credential data
  • build Vite output into OpenId4VpVerifierSite/dist and let the Consumer API MSBuild target copy it into wwwroot/openid4vp-verifier at local build time; generated wwwroot assets are no longer committed
  • build verifier assets in a separate Docker Node stage and copy them into the .NET build stage, so the DHI .NET SDK image does not need npm

Notes

  • For this first version only reference algorithm 3 / XCHACHA20_POLY1305 is handled.
  • Credential status checks remain disabled for the minimal verifier.
  • The Vite build warnings about node:fs externalization and direct eval come from transitive crypto/Credo dependencies.
  • Local targeted MTP test execution starts the integration test assembly but hangs without producing a result in this environment; the integration test project itself builds successfully.

Screenshot

image

@tnotheis tnotheis added the enhancement New feature or request label Sep 3, 2026
@tnotheis
tnotheis force-pushed the feat/openid4vp-verifier-site branch from 63b3d48 to 3e8d6db Compare September 7, 2026 13:21
@tnotheis tnotheis self-assigned this Sep 10, 2026
@tnotheis

Copy link
Copy Markdown
Member Author

@codex review

@chatgpt-codex-connector

chatgpt-codex-connector Bot commented Sep 10, 2026

Copy link
Copy Markdown

Codex Review Summary

This comment shows the latest Codex review activity on this pull request.

Review Status Commit Review trigger
📝 Code Review Completed 2026-09-10T07:05:34.145337Z 59581c9 Manual request
ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review" or "@codex security review".

Codex reacts with 👀 while any review is running, comments if it has suggestions, and reacts with 👍 once all reviews finish with no findings.

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 59581c999c

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment on lines +411 to +415
if (credentialResult.isValid) {
return {
display: extractDisplayFromObject(payload),
isValid: true
};

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P1 Badge Reject standalone JWT credentials without request binding

When TokenContentVerifiablePresentation.value is a standalone signed JWT VC, this branch marks it valid after issuer-signature verification without ever comparing the expected nonce or audience. The same credential can therefore be replayed under any reference and displayed as valid; require a request-bound VP or reject standalone formats that cannot prove the nonce and audience.

AGENTS.md reference: Applications/ConsumerApi/src/OpenId4VpVerifierSite/AGENTS.md:L29-L35

Useful? React with 👍 / 👎.

Comment on lines +155 to +157
if (Array.isArray(value)) {
return value.flatMap(normalizeToken);
}

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P1 Badge Reject invalid members instead of filtering them from arrays

For an input such as [validPresentation, 42], flatMap(normalizeToken) silently removes the invalid member because primitive values normalize to an empty array. Only the valid artifact is subsequently checked, so the whole response is reported valid even though not every supplied presentation element passed validation.

AGENTS.md reference: Applications/ConsumerApi/src/OpenId4VpVerifierSite/AGENTS.md:L37-L39

Useful? React with 👍 / 👎.

Comment on lines +136 to +138
const isValid = verifiedArtifacts.length > 0 && verifiedArtifacts.every((artifact) => artifact.isValid);
const firstCredential = verifiedArtifacts.map((artifact) => artifact.display).find(Boolean) ?? {};
const firstErrorCode = verifiedArtifacts.find((artifact) => !artifact.isValid)?.errorCode;

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P1 Badge Render claims from every verified artifact

When value contains multiple presentations or credentials, validation checks every artifact but retains only the first available display. Claims from all subsequent valid artifacts are discarded, so the verifier does not show all of the subject data that was actually presented.

AGENTS.md reference: Applications/ConsumerApi/src/OpenId4VpVerifierSite/AGENTS.md:L68-L68

Useful? React with 👍 / 👎.

const detailFields = ["createdAt", "expiresAt", "issuer", "publicKey"] as const;
type DetailField = (typeof detailFields)[number];
const validationErrorMessages: Record<PresentationValidationErrorCode, string> = {
[PresentationValidationErrorCode.AudienceMismatch]: "Dieser Nachweis wurde für eine andere Prüfung erstellt. (AudienceMismatch)",

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P1 Badge Remove internal enum names from accessibility messages

Every mapped message exposes an English implementation identifier such as (AudienceMismatch) to screen-reader users through the data-error element. These identifiers are technical rather than user-facing German text and should be removed from all entries while retaining the understandable explanation.

AGENTS.md reference: Applications/ConsumerApi/src/OpenId4VpVerifierSite/AGENTS.md:L66-L66

Useful? React with 👍 / 👎.

display: none !important;
}

.verifier {

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P1 Badge Scope verifier styles under the verifier root

The stylesheet is loaded globally on the onboarding page, but this selector and most following selectors use generic names such as .intro, .details, and .result. They can consequently restyle unrelated markup on this shared page; prefix them with .openid4vp-verifier or #openid4vp-verifier-root as required for this bundle.

AGENTS.md reference: Applications/ConsumerApi/src/OpenId4VpVerifierSite/AGENTS.md:L24-L24

Useful? React with 👍 / 👎.

<meta name="viewport" content="width=device-width, initial-scale=1.0">
</head>
<body>
<body class="openid4vp-verifier-visible">

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Badge Keep onboarding visible until the verifier module starts

When JavaScript is enabled but the module fails to download, parse, or initialize, this server-rendered class immediately hides #app-onboarding-content and leaves every /r/{referenceId} page on the verifier spinner indefinitely. The <noscript> fallback does not cover module-load failures, while main.ts already adds this class after it has successfully found the verifier DOM, so the initial markup should not enable it.

Useful? React with 👍 / 👎.

@tnotheis
tnotheis force-pushed the feat/openid4vp-verifier-site branch from f9cb1c5 to 5b79be5 Compare September 10, 2026 07:05
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

enhancement New feature or request

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant