Integration patterns
Wallet integration
- Obtain SD-JWT + disclosures from the issuer flow (out of scope for OpenAC).
- Ensure
cnf.jwkis present for device binding — enforced inprecompute. See Credential formats. - Run credential binding —
Credential.parseextracts issuer-authenticated input and maps claim names to claim indexes. - Precompute once per credential after keys are available; persist
PrecomputedCredentialsecurely. Typical time: ~2 seconds. - Reblind before Show — handled automatically inside
present(...). Never reuse aprecomputedresult across sessions without going throughpresent, which applies fresh randomness each time. - Present per session with a fresh
verifierNonceandshowInputOptionsdescribing the verifier's policy. Typical time: ~100 ms. - Rotate storage if the device key rotates — a new
cnf.jwkrequires a new precompute.
The profile requires refreshing prepared state before each Show. Reusing the same precomputed result directly across sessions (bypassing present) is not conformant and breaks unlinkability.
Verifier integration
Verification pipeline
Apply checks in this order (Implementation profile §9.1):
parse response
→ check profile version and parameters
→ recover request transcript (nonce, audience, statement)
→ check credential binding identifier
→ check freshness (nonce matches, not expired)
→ check Prepare/Show linkage
→ verify proof
→ evaluate statement semantics
→ check output consistency
→ accept / reject
The order matters. Statement evaluation is only meaningful after transcript, binding, freshness, and linkage have passed.
SDK verifier call
// Load verifying keys only — proving keys stay off the verifier
const result = await openac.verifyProof(proof.serialize(), verifyingKeys);
// result: { valid, expressionResult, deviceKey, verifyMs, error }
Key fields of VerificationResult (types.ts):
| Field | Meaning |
|---|---|
valid | Proof and all binding checks passed. |
expressionResult | The boolean result of the predicate logic expression (what the wallet proved). Verify this matches your policy intent. |
deviceKey | The P-256 public key that signed the verifier nonce. Bind to this if you associate sessions with device keys. |
verifyMs | Time taken to verify. |
error | Present if valid === false. |
valid === true means the proof passed all OpenAC checks. You must also confirm that expressionResult matches your intended policy (e.g. true for a threshold predicate means the condition was met). A proof can be valid while proving a predicate you did not intend.
OpenAC acceptance vs final relying-party acceptance
valid === true and expressionResult === true together constitute OpenAC acceptance — a proof-layer result. Before granting access you must also complete:
| External check | Why |
|---|---|
| Issuer trust | Is the issuer in your trusted list for this credential type? |
| Credential status / revocation | Is the credential still valid? (No in-proof revocation in 0.1.0 — see Revocation overview.) |
| Relying-party authentication | Was the request sent to the correct wallet? |
| User approval | Did the user consciously approve release? |
| Service policy | Does your access policy allow this credential at this time? |
See Implementation profile §10.
Rejection conditions
Reject an OpenAC response if any of the following hold:
- Profile version or parameters are unsupported.
- Credential binding identifier is unknown or unsupported.
- Transcript binding fails: nonce, audience, or statement does not match the request.
- Freshness check fails: nonce already used, request expired, or freshness material missing.
- Prepare/Show linkage fails: the Show proof does not commit to the same messages as Prepare.
- Proof verification fails.
- Declared statement type is unsupported.
- Output values are inconsistent with the proven statement.
- Response carries an undeclared extension or downgrade indicator.
Issuer assumptions
- P-256 / ES256 issuer keys in the PoC (trusted per paper's security section).
- Disclosure digests must match issuer-issued
_sdentries — malformed issuance surfaces asINVALID_JWT/MISSING_DISCLOSUREerrors in the SDK. See Errors.
Revocation hooks
There is no precompute/present parameter for on-chain or accumulator revocation witnesses in 0.1.0. Scenario planning for future in-proof checks appears in OpenAC Studio rulesets. See Revocation overview for the design space.
Threat-model tooling
wallet-unit-poc/openac-studio models verifier/issuer collusion and revocation handling for educational walkthroughs — not required for bare SDK integration.