| name | verifido-integration |
| description | Integrates HiTRUST VeriFido FIDO2/WebAuthn using VeriFido .NET 1.0.x NuGet packages (current 1.0.2): package selection, BFF embed vs RP host topology, IVeriFidoGateway adapters, FidoFlowService, rpId/ApiBaseUrl configuration, stateless rpTxId/txId echo, and testing. Use when working with VeriFido, FIDO2, WebAuthn, Passkey, FidoFlowService, rpId, VeriFido.Core, Rp.AspNetCore, or BFF FIDO integration. |
VeriFido .NET Integration
Guides AI agents to integrate HiTRUST VeriFido FIDO2/WebAuthn using the VeriFido .NET 1.0.x NuGet packages in this repository (current release: 1.0.2).
Scope: Package selection, RP host setup, BFF embedding with VeriFido.Core, configuration, stateless ceremony correlation, public API boundaries, and tests.
Out of scope: Full-stack BFF OTP/token APIs (implement in your app on top of IFidoFlowService); generic WebAuthn without VeriFido.
When to use this skill
Load this skill when the task involves:
- HiTRUST VeriFido API or FIDO2 / WebAuthn / Passkey integration in .NET
FidoFlowService, IVeriFidoGateway, rpId, or VeriFido.Core
VeriFido.Rp.AspNetCore (AddVeriFidoRp, MapVeriFidoRpEndpoints)
- Embedding FIDO in an existing BFF vs running a standalone RP host
- Errors like
RpTxId is required or startup ApiBaseUrl validation failures
Package decision tree
Need /fido2/* HTTP endpoints with minimal code?
→ VeriFido.Rp.AspNetCore (pulls Contracts, Abstractions, Core)
Need flow logic only in an existing ASP.NET Core BFF?
→ VeriFido.Contracts + VeriFido.Abstractions + VeriFido.Core
→ Do NOT reference Rp.AspNetCore unless you want its controllers
Need shared DTOs only?
→ VeriFido.Contracts
Need interfaces for adapters/tests?
→ VeriFido.Abstractions
| Package | Who references it | Responsibility |
|---|
VeriFido.Contracts | BFF, RP, tests | Request/response and flow DTOs |
VeriFido.Abstractions | BFF, RP, tests | IVeriFidoGateway, IFidoTransactionStore, IAuthSessionIssuer |
VeriFido.Core | BFF, RP | FidoFlowService, IFidoFlowService (framework-agnostic) |
VeriFido.Rp.AspNetCore | Standalone RP host only | DI extensions, Fido2Controller, internal HTTP client |
Install RP host:
dotnet add package VeriFido.Rp.AspNetCore
Monorepo project reference:
<ProjectReference Include="..\..\verifido-dotnet\src\VeriFido.Rp.AspNetCore\VeriFido.Rp.AspNetCore.csproj" />
Architecture topologies
Production: BFF direct to VeriFido
Mobile / Web Client → BFF (your app API)
↓ IVeriFidoGateway
HiTRUST VeriFido API
- BFF references Contracts + Abstractions + Core only.
ApiBaseUrl = VeriFido API URL (e.g. https://t-fido.hitrustpay.com.tw/veri-fido-api).
RpId = production public domain (may differ from BFF hostname).
Development: BFF → RP proxy → VeriFido
Mobile App → BFF (UseRpProxy) → RP Host (public rpId domain)
↓
VeriFido API
- BFF
ApiBaseUrl may point at the RP host URL during dev.
- RP host
ApiBaseUrl must still point at the VeriFido API, never at itself.
- Mobile app
rpId and BFF RpId must match the RP host public domain.
- Expose RP via HTTPS tunnel (e.g. Cloudflare) for real-device Passkey tests.
See reference.md for endpoint and environment matrices.
BFF integration pattern
Reference Contracts, Abstractions, Core — not VeriFido.Rp.AspNetCore.
Required adapters
| Interface | Your implementation |
|---|
IVeriFidoGateway | HTTP to VeriFido (or to RP proxy in dev) |
IFidoTransactionStore | Session/Redis store, or noop if client echoes ids |
IAuthSessionIssuer | Map verified assertion → app tokens (project-specific) |
Orchestration
Register and inject FidoFlowService via IFidoFlowService:
services.AddScoped<IVeriFidoGateway, YourVeriFidoGateway>();
services.AddScoped<IFidoTransactionStore, YourTransactionStore>();
services.AddScoped<IAuthSessionIssuer, YourAuthSessionIssuer>();
services.AddScoped(_ => new VeriFidoFlowSettings
{
RpId = settings.RpId,
SystemId = settings.SystemId,
IsPaymentFromRp = settings.IsPaymentFromRp
});
services.AddScoped<IFidoFlowService, FidoFlowService>();
Your controllers call IFidoFlowService — bind (GetBindOptionsAsync / SubmitBindResultAsync) and login (GetLoginOptionsAsync / SubmitLoginResultAsync).
Do NOT depend on internals
IVeriFidoService / VeriFidoService are internal to Rp.AspNetCore.
- Public transport boundary:
IVeriFidoGateway.
- Do not copy or embed duplicate
Fido.Shared types; use VeriFido.Contracts.
RP host pattern
For a standalone RP that exposes /fido2/*:
builder.Services.AddVeriFidoRp(builder.Configuration);
var app = builder.Build();
app.UseVeriFidoRp();
app.UseVeriFidoRpStaticFiles();
app.MapVeriFidoRpEndpoints();
Public extension entry points: AddVeriFidoRp, UseVeriFidoRp, MapVeriFidoRpEndpoints.
Runnable reference: samples/RpHost — see samples/RpHost/README.md. The built-in test page covers bind, login, and remove (POST /fido2/user/remove).
Configuration rules
All settings bind under the VeriFido section (VeriFidoSettings.SectionName).
| Key | Rule |
|---|
ApiBaseUrl | HiTRUST VeriFido API base URL — never the RP proxy URL on RP hosts |
RpId | Public RP domain / scenario id (Passkey association domain) |
SystemId | HiTRUST-provided system id |
ApiKey | Secret; required in Production; never commit or expose via /fido2/config |
Environment variables: VeriFido__ApiKey, VeriFido__RpId, etc.
VeriFidoSettingsValidator (RP hosts)
Registered by AddVeriFidoRp with ValidateOnStart. Fails when:
- Required keys missing (
RpId, SystemId, ApiBaseUrl; ApiKey in non-Development)
ApiBaseUrl looks like an RP proxy (fido.*, localhost without VeriFido path, etc.)
ApiKey header format
Gateway sends: ApiKey: {RpId}||{ApiKey} to the VeriFido API. Redact secrets in logs.
Full key reference: docs/configuration.md.
Stateless flow checklist
VeriFido uses a stateless ceremony design. Both rpTxId and txId must survive step 1 → step 2.
Attestation (bind):
POST /fido2/attestation/options → response includes rpTxId + txId
POST /fido2/attestation/result → client echoes rpTxId + txId
Assertion (login):
POST /fido2/assertion/options → response includes rpTxId + txId
POST /fido2/assertion/result → client echoes rpTxId + txId
FidoFlowService generates rpTxId when VeriFido omits it. Step 2 rejects missing ids.
| Symptom | Fix |
|---|
RpTxId is required | Controller or client dropped rpTxId on result step |
TxId is required | Client did not echo txId from options response |
| Startup validation fails | RP host ApiBaseUrl points at proxy, not VeriFido API |
Controllers must map client DTOs completely — see Fido2Controller forwarding RpTxId = clientRequest.RpTxId.
Public API stability (1.0)
Stable (depend on these):
AddVeriFidoRp, UseVeriFidoRp, MapVeriFidoRpEndpoints
IVeriFidoGateway, IFidoTransactionStore, IAuthSessionIssuer, IFidoFlowService
FidoFlowService, VeriFido.Contracts DTOs
VeriFidoSettings, VeriFidoSettingsValidator
Internal (do not reference):
IVeriFidoService, VeriFidoService
RpVeriFidoGateway, SessionFidoTransactionStore (implementation details; replicate pattern in BFF)
Treat success return codes 0, 0000, ok (case-insensitive) as success.
Testing guidance
Unit tests (Core)
Mock IVeriFidoGateway, IFidoTransactionStore, IAuthSessionIssuer. Follow patterns in tests/VeriFido.Core.Tests/FidoFlowServiceTests.cs:
- Options step fills
rpTxId when VeriFido omits it
- Result step uses echoed
rpTxId / txId in stateless mode
- Missing ids return failure
Integration tests (RP)
Use WebApplicationFactory with a mocked IVeriFidoGateway — see tests/VeriFido.Rp.AspNetCore.Tests/Fido2EndpointTests.cs:
/fido2/config does not expose apiKey
- Attestation options returns
rpTxId
- Attestation result forwards
rpTxId to gateway
Commands
From repository root (requires just):
just build
just test
just pack
just setup
just dev
Equivalent dotnet commands:
dotnet build VeriFido.sln
dotnet test VeriFido.sln
dotnet pack VeriFido.sln -c Release -o artifacts
Implementation checklist (BFF)
Copy and track when adding FIDO to an existing BFF:
VeriFido BFF integration:
- [ ] 1. Add NuGet refs: Contracts, Abstractions, Core (not Rp.AspNetCore)
- [ ] 2. Configure VeriFido section (ApiBaseUrl, RpId, SystemId, ApiKey from secrets)
- [ ] 3. Implement IVeriFidoGateway (HTTP + ApiKey header format)
- [ ] 4. Implement IFidoTransactionStore (or noop with client echo)
- [ ] 5. Implement IAuthSessionIssuer (post-login tokens)
- [ ] 6. Register VeriFidoFlowSettings + FidoFlowService
- [ ] 7. Wire app controllers to IFidoFlowService
- [ ] 8. Ensure result endpoints forward rpTxId and txId from client
- [ ] 9. Add unit tests (mock gateway) + integration tests for your routes
- [ ] 10. Align mobile rpId with RpId; configure AASA / assetlinks if native Passkeys
Anti-patterns
| Anti-pattern | Why it fails |
|---|
RP host ApiBaseUrl = own proxy URL | VeriFidoSettingsValidator fails; infinite/wrong routing |
Dropping rpTxId in result controllers | RpTxId is required at runtime |
Depending on IVeriFidoService | Internal; breaks across package versions |
Using Web SDK for Rp.AspNetCore package | Package uses Microsoft.NET.Sdk + FrameworkReference, not Web SDK |
| Embedding duplicate Fido.Shared DTOs | Drift from VeriFido.Contracts; use the package |
Exposing ApiKey in /config | Security leak; RP config endpoint is public |
Trusting request username over VeriFido verified identity on login | Wrong user token issuance (BFF responsibility) |
Verification (after implementing)
When reviewing security, token issuance, OTP gates, or marking integration complete, load verifido-verification-gate (.cursor/skills/verifido-verification-gate/SKILL.md). It selects proof surfaces and reports remaining risk — use alongside this skill, not instead of it.
Repository documentation
For endpoint tables, environment matrix, and package versions, see reference.md.