aidbox-health-card-issue: spec-conformant SMART Health Cards + QR/file/viewer#39
Merged
Merged
Conversation
…e/viewer Make issued cards pass strict SMART Health Cards verification and add the missing delivery surfaces (QR, .smart-health-card file) plus an in-browser verifier. Conformance fixes: - Actually DEFLATE the JWS payload before signing (SignJWT declared zip:DEF but never compressed); now deflateRaw + CompactSign. - kid = base64url SHA-256 JWK thumbprint (RFC 7638), read from the JWK so the signing kid always matches the published JWKS. - Minify bundle refs to short resource:N URIs (fullUrl + Reference.reference). - iss now matches the JWKS location; JWKS op made public (allow policy) + CORS. - includeIdentityClaim treated as repeating string claim paths (not boolean). Features: - Accept both #covid19 (VCI) and generic Immunization/Observation credentialType (uri/dateTime datatypes). - Delivery: shc:/ QR (numeric-mode encoder), .smart-health-card download, /demo/issue + /demo/patients, and an Issue/Verify viewer (WebCrypto ES256). - README with sequence diagrams + ADR-005; retire key-utils. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
… drop dangling refs
Follow-up conformance hardening after comparing against the official
health-cards-dev-tools validator and reference issuers (dvci, kill-the-clipboard):
- QR: switch the encoder to error-correction level L (EC-M forced version 24;
the validator rejects QR > version 22). A real card now fits ~v17.
- Compress the JWS payload at DEFLATE level 9 (card shrinks ~1037 -> ~708 chars).
- Minification: drop empty elements (""/[]/{}) and dangling references (a card
reference must resolve to a resource:N URI); keep Reference.display.
- README: shorten diagram labels, JWKS note as a list, drop Layout + ADR link.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…-link example The smart-health-link example uses aidbox 8080 + app 3000; this example now uses aidbox 8081 + app 3001 (app internal port + Aidbox App endpoint + iss all updated) so both can run at the same time. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…ssue tab
The Issue tab called the unauth /demo/issue stand-in without showing the real
FHIR operation. Add a panel rendering the exact POST
/fhir/Patient/{id}/$health-cards-issue request (auth header, Parameters body)
and its Parameters { verifiableCredential } response.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…ADME cleanup - resourceLink (OUT): map each minified resource:N entry to its live FHIR URL (bundledResource -> hostedResource, vcIndex 0); reuses the bundle-builder refMap; hostedResource base from FHIR_PUBLIC_BASE_URL (default: iss origin + /fhir). - Viewer: expose _since on the Issue tab (forwarded through /demo/issue), and show resourceLink in the $health-cards-issue response panel. - README/ADR: drop resourceLink from out-of-scope; document credentialType (#covid19 -> CVX) mapping; restore features frontmatter; link the smart-health-link example. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
resourceLink.hostedResource is always derived from the issuer origin + /fhir (one less knob). Revert the README H1 to 'SMART Health Cards Issue Operation'. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…package
- credentialValueSet (IN): filter resources by content — keep only those whose
code is a member of the ValueSet, via Aidbox ValueSet/$validate-code.
- Load the real hl7.fhir.uv.shc-vaccination#1.0.0 package via
BOX_BOOTSTRAP_FHIR_PACKAGES (':'-separated) for its immunization-all-cvx
ValueSet — no hand-authored ValueSet.
- Viewer: add a credentialValueSet dropdown (forwarded through /demo/issue,
shown in the operation request panel).
- Drop the filterByValueSet stub; remove credentialValueSet from out-of-scope.
Verified: covid19 + the CVX ValueSet issues a card (CVX 208 is a member);
Observation + the same ValueSet filters the LOINC lab out.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…zation for the credentialValueSet demo - Viewer Issue form: credentialType, credentialValueSet, includeIdentityClaim are now repeatable (+ buttons); credentialValueSet + includeIdentityClaim live under an Advanced section. Arrays are forwarded through /demo/issue and shown in the operation request panel. - credentialValueSet is now string[] end to end (multiple = logical AND). - init-bundle: add a SNOMED-coded Immunization so credentialValueSet filtering between two immunizations is demonstrable (CVX kept, SNOMED filtered by the CVX ValueSet — validated locally). Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
The Verify result now explains what happened (6-step check with pass/fail marks) and shows what's inside the JWS: decoded header (alg/zip/kid), payload claims (iss, nbf as a date, exp, vc.type, fhirVersion), and the FHIR bundle — instead of a single opaque 'signed by …' line. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…option SnomedVaccineCodes is a SNOMED descendent-of filter that the configured external\ntx server doesn't resolve here (returns false for every code), so it only ever\nproduced empty results and confused the AND semantics. Keep immunization-all-cvx. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…uct code The second immunization used SNOMED 86198006 (Influenza vaccine), which is NOT a\ndescendant of 787859002 (Vaccine product), so SnomedVaccineCodes never matched it\nand that credentialValueSet option always returned empty. Use 1119349007\n(COVID-19 mRNA vaccine), a real Vaccine-product descendant the external tx\nresolves. Re-add SnomedVaccineCodes to the viewer — now Immunization + that\nValueSet keeps only the SNOMED shot, Immunization + immunization-all-cvx keeps\nonly the CVX shot. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
… $fhir-package-install Use the expected value sets: install cards.smarthealth.terminology (the official\nSHC terminology, not on any FHIR registry) via the $fhir-package-install operation\nin the init bundle, passing the package URL directly\n(https://terminology.smarthealth.cards/package.tgz) — no tarball committed or\nmounted. Drop hl7.fhir.uv.shc-vaccination from BOX_BOOTSTRAP. The viewer's credentialValueSet now offers immunization-covid-cvx (the COVID-\nspecific, enumerated CVX set — validated locally). SNOMED value sets are dropped:\nthey enumerate SNOMED extension codes the configured external tx doesn't resolve. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
A card that exceeds single-QR capacity (> version 22) is not an issuance error — the card is valid and still delivered via file/JWS. Show that note in the QR caption instead of the bottom error box; real issuance failures stay in the error box. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Upgrades the
aidbox-health-card-issueexample so issued cards pass strict SMART Health Cards verification, and adds the delivery surfaces that were missing (QR,.smart-health-cardfile) plus an in-browser verifier.Conformance fixes
The previous
verifiableCredentialdid not verify. Fixed (per spec.smarthealth.cards + HL7 IG v1.0.0):SignJWTsetzip:"DEF"but never compressed the payload; nowdeflateRaw+CompactSign.kid= base64url SHA-256 JWK thumbprint (RFC 7638) — read from the JWK so the signingkidalways matches the published JWKS.resource:Nrefs —Bundle.entry.fullUrl+ allReference.referencerewritten to shortresource:0/1….issmatches the JWKS location; JWKS op made public (allowpolicy) + CORS (Aidbox owns its own/.well-known/jwks.json, so ours stays namespaced under the app path).includeIdentityClaimtreated as a repeating string of claim paths (not boolean).Features
https://smarthealth.cards#covid19(VCI) and genericImmunization/ObservationcredentialType (uri/dateTime datatypes).shc:/QR (numeric-mode encoder, versions ≤27),.smart-health-carddownload,/demo/issue+/demo/patients, and an Issue/Verify viewer (WebCrypto ES256 +deflate-raw).adr/005-delivery-and-conformance.md;key-utilsretired.Verification
$health-cards-issue→verifiableCredential; public JWKS; verified as a real verifier (readiss→ fetch its JWKS → ES256 signature valid).id/ 0text/ 0meta/ 0Coding.display;collection+resource:0/1;fhirVersion 4.0.1.tscbuild + lint clean; offline smoke (24 checks) pass.Notes / scope
issishttp://localhost:8080(spec wants https + no trailing slash) — documented local-dev deviation.credentialValueSetaccepted but not filtered;resourceLinkOUT param and formal VCI$validateleft out of scope.🤖 Generated with Claude Code