How it works
A plain-language walkthrough of what happens when Tessaliq verifies an identity attribute — the actors, the protocols, the cryptography and what Tessaliq does not do. Intended for developers, architects and technical-minded prospects who want to know before integrating.
The four actors
A verification flow always involves the same four parties:
- User — the person whose age or attribute is being verified.
- Wallet — the EUDI Wallet holding signed credentials (France Identité, a national wallet, or the EU AV reference app in transitional mode).
- Relying Party (RP) — the SaaS application that needs to verify something before providing a service (e.g. age-gate for a website).
- Tessaliq verifier — validates the cryptographic presentation received from the wallet on behalf of the RP, and returns a signed receipt.
flowchart LR
U([User]) ---|holds credentials| W([Wallet])
U ---|initiates verification| RP([Relying Party SaaS])
RP <-->|OID4VP / DC API| W
RP -->|verification request| T[Tessaliq verifier]
T -->|signed receipt| RP
T -.->|validates against| TA[(Trust anchors / IACA / JWKS)]
classDef actor fill:#18181b,stroke:#52525b,color:#f4f4f5
classDef core fill:#27272a,stroke:#a5b4fc,color:#f4f4f5
class U,W,RP actor
class T core
The diagram above is logical. In practice Tessaliq runs as an API that the RP calls server-side, plus an optional Web SDK that runs in the user's browser to coordinate with the Digital Credentials API.
The OpenID4VP flow
OpenID for Verifiable Presentations (OID4VP 1.0 Final) is the standard protocol Tessaliq uses to request and receive a presentation from a wallet. Here is a full sequence.
sequenceDiagram
autonumber
participant RP as Relying Party
participant T as Tessaliq API
participant U as User browser
participant W as EUDI Wallet
RP->>T: POST /v1/sessions (policy)
T-->>RP: session_id + request_uri
RP->>U: redirect / QR with request_uri
U->>W: open request_uri
W->>T: GET signed Authorization Request JWT (JAR)
T-->>W: request object (policy, claims, nonce)
W->>W: user consents, selective disclosure
W->>T: POST vp_token (OID4VP response)
T->>T: verify signature, trust chain, nonce, disclosures
T->>T: persist session state: verified
RP->>T: GET /v1/sessions/{id}
T-->>RP: state + signed receipt (JWT ES256)
RP->>RP: verify receipt offline via published JWKS
Two details matter:
- Step 5 — the wallet fetches a signed Authorization Request (JAR). The request is not sent in URL parameters; it's a signed JWT the wallet validates before showing the user what they are about to disclose. Tessaliq signs these requests with an ES256 key whose certificate chains to a known trust anchor (X.509 SAN DNS by default, or X.509 hash for HAIP 1.0 Final).
- Step 8 — Tessaliq validates four things on the response: (a) the issuer signature on the credential chains to a trusted IACA / JWKS, (b) the disclosures match the issuer-signed hashes, (c) the nonce matches the session, (d) optional key-binding JWT if the policy requires it.
The Digital Credentials API flow
The W3C Digital Credentials API (DC API) is the newer browser-native path, available in Chrome (behind a flag in Chrome 128+) and Safari 26+. Instead of redirecting the user to their wallet via a deep-link, the browser itself brokers the request.
sequenceDiagram
autonumber
participant RP as Relying Party (SaaS)
participant W as User browser
participant T as Tessaliq API
participant Wal as EUDI Wallet
RP->>T: POST /v1/sessions (policy)
T-->>RP: session_id + DC API request object
RP->>W: invoke navigator.credentials.get(digital)
W->>Wal: OS-level credential chooser
Wal->>W: user selects credential, consents
W-->>RP: encrypted response (JWE)
RP->>T: POST /v1/openid4vp/response (JWE payload)
T->>T: decrypt with HPKE, verify inside, mark verified
RP->>T: GET /v1/sessions/{id}
T-->>RP: state + signed receipt
The DC API path uses HPKE (RFC 9180) for the end-to-end encryption of the presentation: the wallet encrypts the response with an ephemeral key derived for the session, and only the Tessaliq API can decrypt it. Even the RP's own frontend never sees the cleartext credential.
Cryptography summary
Tessaliq keeps the crypto stack narrow and standard:
- ES256 (ECDSA P-256 with SHA-256) — used for issuer credential signatures, for JAR signing, and for the signed receipt Tessaliq returns to the RP.
- HPKE (RFC 9180) — used to encrypt the wallet response in the DC API path. Mode: DHKEM(P-256, HKDF-SHA256) with AES-128-GCM or AES-256-GCM.
- JWE (ECDH-ES + A128GCM / A256GCM) — the legacy
response wrapping still used in some OID4VP HAIP flows
(
direct_post.jwt). - SHA-256 — disclosure hashes for SD-JWT-VC and mdoc.
No custom crypto, no unreviewed primitives. Everything chains to public standards that a security auditor can review against ISO, IETF and OpenID specs. Tessaliq publishes its full list of supported standards and their OIDF conformance plans.
Trust chain — where confidence comes from
"Trusting" a credential presentation means chaining the signature back to a known authority. Tessaliq supports two trust models in parallel:
flowchart TB
subgraph mdoc[mdoc ISO 18013-5 X.509 chain]
IACA[IACA root e.g. France Identite IACA] --> DS[Document Signer Certificate]
DS --> C1[mdoc credential signed by DS]
end
subgraph sdjwt[SD-JWT-VC JWKS]
REG[Trusted Issuer Registry JWKS endpoints] --> IK[Issuer public key]
IK --> C2[SD-JWT-VC credential signed by issuer]
end
T[Tessaliq verifier] --> IACA
T --> REG
style T fill:#27272a,stroke:#a5b4fc,color:#f4f4f5
- mdoc (ISO 18013-5) — the classical mobile ID
format. Each credential carries an X.509 certificate chain ending
in an IACA root. Tessaliq ships bundled IACA roots for the France
Identité qualification environment and for the EU AV reference
implementation, and can load additional roots via the
TRUSTED_IACA_CERTSenvironment variable. - SD-JWT-VC — the newer IETF format. Issuers publish a JWKS endpoint; Tessaliq resolves the issuer public key via an internal issuer registry configured by the operator.
When the EU rolls out production wallets under eIDAS 2, the authoritative source shifts to the ETSI Trusted List published through the eIDAS Dashboard. Tessaliq will consume that list rather than shipping bundled certificates once that channel is stable.
The signed receipt
Every successful verification produces a compact JWT receipt, signed
ES256 with a key whose public JWKS is exposed at
/v1/keys/jwks. The RP can verify the receipt offline
without calling Tessaliq again — useful for long-term audit storage.
Sample payload:
{
"iss": "https://api.tessaliq.com",
"sub": "session:c358892b-7399-4c72-ac43-ac5a6b42528a",
"iat": 1776436542,
"exp": 1776440142,
"policy": "av_age_18_plus",
"verified": true,
"proof_hash": "sha256:9b3f2e...",
"org_id": "3728fa54-6c70-4a60-8a63-87b1da5514b5",
"credential_format": "mdoc",
"attestation_provider": "mock://staging"
}
Concretely : a CNIL or ARCOM auditor asking for proof of verification
receives a cryptographic artefact, not a request log. The
proof_hash binds the receipt to the exact presentation
that was verified, so replaying a past receipt on a new session is
detectable.
What Tessaliq does not do
Scope clarity, plainly stated:
- No KYC document scanning — no OCR, no MRZ, no liveness detection. Tessaliq consumes credentials issued by a wallet; it does not replace them.
- No biometric verification — no face matching, no fingerprint. That belongs to the wallet's own onboarding.
- No fraud scoring — no device fingerprinting, no behavioural signals. Pair with a dedicated fraud tool if that is a requirement.
- No data retention of PII — the verifier never stores the user's name, birth date, or identity documents. It keeps session metadata (nonce, policy, verification outcome, proof hash) for audit; no attributes.
- No public self-host at this stage — Tessaliq is in early access, deployment patterns for third parties are being designed. Self-host is on the roadmap, not shipped.
Next — integrate
If you want to see how to wire this into your own SaaS, head to integration. For the full list of supported standards and public OIDF conformance runs, see compliance.