Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -270,6 +270,8 @@ FakesAssemblies/
# Node.js Tools for Visual Studio
.ntvs_analysis.dat
node_modules/
Applications/ConsumerApi/src/OpenId4VpVerifierSite/dist/
Applications/ConsumerApi/src/wwwroot/openid4vp-verifier/

# Visual Studio 6 build log
*.plg
Expand Down
27 changes: 27 additions & 0 deletions Applications/ConsumerApi/src/ConsumerApi.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,9 @@

<PropertyGroup>
<UserSecretsId>f114fba8-95dd-4fee-8385-af8e8a343c68</UserSecretsId>
<OpenId4VpVerifierSiteRoot>$(MSBuildProjectDirectory)/OpenId4VpVerifierSite/</OpenId4VpVerifierSiteRoot>
<OpenId4VpVerifierDistRoot>$(OpenId4VpVerifierSiteRoot)dist/openid4vp-verifier/</OpenId4VpVerifierDistRoot>
<OpenId4VpVerifierWwwRoot>$(MSBuildProjectDirectory)/wwwroot/openid4vp-verifier/</OpenId4VpVerifierWwwRoot>
</PropertyGroup>

<ItemGroup>
Expand Down Expand Up @@ -42,4 +45,28 @@
<Delete Files="$(ProjectDir)appsettings.override.json" />
<Copy SourceFiles="..\..\..\appsettings.override.json" DestinationFolder="$(ProjectDir)" UseHardlinksIfPossible="true" />
</Target>

<Target Name="InstallOpenId4VpVerifierSiteDependencies"
Inputs="$(OpenId4VpVerifierSiteRoot)package-lock.json"
Outputs="$(OpenId4VpVerifierSiteRoot)node_modules/.package-lock.json"
Condition="'$(DesignTimeBuild)' != 'true' and '$(SkipOpenId4VpVerifierBuild)' != 'true'">
<Exec WorkingDirectory="$(OpenId4VpVerifierSiteRoot)" Command="npm ci" />
</Target>

<Target Name="BuildOpenId4VpVerifierSite"
BeforeTargets="ResolveProjectStaticWebAssets"
DependsOnTargets="InstallOpenId4VpVerifierSiteDependencies"
Condition="'$(DesignTimeBuild)' != 'true' and '$(SkipOpenId4VpVerifierBuild)' != 'true'">
<Exec WorkingDirectory="$(OpenId4VpVerifierSiteRoot)" Command="npm run build" />
<RemoveDir Directories="$(OpenId4VpVerifierWwwRoot)" />
<MakeDir Directories="$(OpenId4VpVerifierWwwRoot)" />
<ItemGroup>
<OpenId4VpVerifierDistFiles Include="$(OpenId4VpVerifierDistRoot)**/*" />
</ItemGroup>
<Copy SourceFiles="@(OpenId4VpVerifierDistFiles)"
DestinationFiles="@(OpenId4VpVerifierDistFiles->'$(OpenId4VpVerifierWwwRoot)%(RecursiveDir)%(Filename)%(Extension)')" />
<ItemGroup>
<Content Include="$(OpenId4VpVerifierWwwRoot)**/*" />
</ItemGroup>
</Target>
</Project>
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ public AppOnboardingController(IOptions<ConsumerApiConfiguration> configuration,
[ProducesResponseType(StatusCodes.Status302Found)]
[ProducesResponseType(StatusCodes.Status400BadRequest)]
[AllowAnonymous]
public IActionResult GetReference([FromRoute(Name = "referenceId")] string? _, [FromQuery] string? app)
public IActionResult GetReference([FromRoute(Name = "referenceId")] string? referenceId, [FromQuery] string? app)
{
if (_configuration == null)
return NotFound();
Expand All @@ -38,7 +38,7 @@ public IActionResult GetReference([FromRoute(Name = "referenceId")] string? _, [

var stores = ListStoresForUserAgent(selectedAppConfiguration);

return View("AppOnboarding", new AppOnboardingModel(selectedAppConfiguration, stores));
return View("AppOnboarding", new AppOnboardingModel(referenceId, selectedAppConfiguration, stores));
}

private List<AppOnboardingModel.AppStore> ListStoresForUserAgent(ConsumerApiConfiguration.AppOnboardingConfiguration.App appConfiguration)
Expand Down Expand Up @@ -110,8 +110,9 @@ public App(ConsumerApiConfiguration.AppOnboardingConfiguration.App app)

public class AppOnboardingModel
{
public AppOnboardingModel(ConsumerApiConfiguration.AppOnboardingConfiguration.App config, List<AppStore> links)
public AppOnboardingModel(string? referenceId, ConsumerApiConfiguration.AppOnboardingConfiguration.App config, List<AppStore> links)
{
ReferenceId = referenceId;
AppId = config.Id;
AppDisplayName = config.DisplayName;
AppDescription = config.Description;
Expand All @@ -121,6 +122,7 @@ public AppOnboardingModel(ConsumerApiConfiguration.AppOnboardingConfiguration.Ap
AppIconUrl = config.IconUrl;
}

public string? ReferenceId { get; }
public string AppId { get; }
public string AppDisplayName { get; }
public string AppDescription { get; set; }
Expand Down
13 changes: 12 additions & 1 deletion Applications/ConsumerApi/src/Dockerfile
Original file line number Diff line number Diff line change
@@ -1,14 +1,25 @@
FROM node:24-bookworm-slim@sha256:ba849c60be29959425b8734d57b8b4b7d56f98edd9504c9af091d5281095a71e AS openid4vp-verifier-build-env

WORKDIR /src/Applications/ConsumerApi/src/OpenId4VpVerifierSite

COPY ["Applications/ConsumerApi/src/OpenId4VpVerifierSite/package.json", "Applications/ConsumerApi/src/OpenId4VpVerifierSite/package-lock.json", "./"]
RUN npm ci

COPY ["Applications/ConsumerApi/src/OpenId4VpVerifierSite/", "./"]
RUN npm run build

FROM dhi.io/dotnet:10.0.302-sdk@sha256:e18fceb745383b13f9c334a22c4c17943770129a5601033d3dfc1beff2cec17e AS build-env

ARG VERSION

WORKDIR /src

COPY . .
COPY --from=openid4vp-verifier-build-env /src/Applications/ConsumerApi/src/OpenId4VpVerifierSite/dist/openid4vp-verifier ./Applications/ConsumerApi/src/wwwroot/openid4vp-verifier

RUN dotnet restore /p:ContinuousIntegrationBuild=true "Applications/ConsumerApi/src/ConsumerApi.csproj"
RUN dotnet restore /p:ContinuousIntegrationBuild=true "Applications/HealthCheck/src/HealthCheck.csproj"
RUN dotnet publish /p:ContinuousIntegrationBuild=true --configuration Release --output /app/publish --no-restore "Applications/ConsumerApi/src/ConsumerApi.csproj"
RUN dotnet publish /p:ContinuousIntegrationBuild=true /p:SkipOpenId4VpVerifierBuild=true --configuration Release --output /app/publish --no-restore "Applications/ConsumerApi/src/ConsumerApi.csproj"
RUN dotnet publish /p:ContinuousIntegrationBuild=true --configuration Release --output /app/publish/health --no-restore "Applications/HealthCheck/src/HealthCheck.csproj"

FROM dhi.io/aspnetcore:10.0.10-debian13@sha256:36f56fe5ec5c2ac63d1451b43eb6ef00f981c9454159e3a45087a2b9071d405d
Expand Down
29 changes: 29 additions & 0 deletions Applications/ConsumerApi/src/OpenId4VpVerifierSite/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
# OpenID4VP Verifier Site

This Vite application builds the static OpenID4VP verifier bundle that is embedded into the Consumer API `/r/{referenceId}` onboarding page.

## Build

```sh
npm install
npm run build
```

The Vite build output is written to `dist/openid4vp-verifier` and exposes fixed asset names under `/openid4vp-verifier/assets/`.

During the Consumer API build, MSBuild runs the Vite build and copies the generated files into `../wwwroot/openid4vp-verifier`. The copied `wwwroot` files are build artifacts and are not committed.

## Input

The bundle reads the NMSHD reference fragment from the current `/r/{referenceId}` URL. The fragment is base64url encoded and contains `algorithm|key|forIdentity|passwordProtection`. For this first version, only algorithm `3` (`XCHACHA20_POLY1305`) is supported.

The referenced Token or RelationshipTemplate content is fetched from the Consumer API. If the decrypted JSON has `@type: "TokenContentVerifiablePresentation"`, its `value` is verified as a presented credential using the reference id as expected nonce and `defaultPresentationAudience` as expected audience. Otherwise, the original onboarding page is shown.

Credential display values are extracted from the Verifiable Presentation. Missing values are omitted instead of being replaced with sample/default credential data.

Optional validation parameters:

- `nonce` or `expected_nonce`: expected presentation challenge.
- `audience` or `client_id`: expected presentation audience. If omitted, the current origin is used.

The implementation performs a minimal browser-side validation using `@credo-ts/core` and `@credo-ts/openid4vc` types. NMSHD token content is decrypted with `@nmshd/crypto`. Credential status checks are disabled for this first version.
Loading