Assurance level and security model
There is no single “secure” configuration that fits every use case. The right security model for issuance and verification depends on how much assurance you need in the identity or data you are exchanging, and that level of assurance is determined by several factors working together:
- The protocol features you enable: for example response encryption, the issuance flow, and whether presentations use a redirect-based same-device flow or a cross-device flow. Each feature changes the threat model.
- The issuers you trust: a credential is only as trustworthy as the issuer that signed it and the trusted entities you configure to accept. Accepting any issuer is very different from accepting a small set of vetted, high-assurance issuers.
- The assurance level of the credential itself: how the credential was originally issued (was the holder identity-proofed? is the credential bound to a device key?) caps the assurance you can derive from presenting it. A self-asserted email credential cannot give you the same assurance as a government-issued, device-bound identity credential, no matter how securely it is presented.
Think of these as a chain: your effective assurance is bounded by the weakest link. A perfectly secured transport for a low-assurance credential still only gives you a low-assurance result.
Recommendation: follow HAIP
For most use cases we recommend following the OpenID4VC High Assurance Interoperability Profile (HAIP) 1.0 for both issuance and verification. HAIP is a profile of the OpenID4VC family of specifications that pins down a concrete, interoperable, high-assurance set of choices (credential formats, cryptographic algorithms, key binding, and flows), so that issuers, wallets, and verifiers that all follow HAIP can interoperate while meeting a high security bar.
Paradym supports HAIP out of the box (see standards and protocols). Concretely, to align with a high-assurance model we recommend the following:
These are recommendations for a high-assurance setup. Lower-assurance use cases may relax some of them, but you should do so deliberately and understand what each choice means for your threat model.
Always enable response encryption
When verifying, enable response encryption so the authorization response from the wallet is encrypted (response_mode direct_post.jwt) rather than sent in the clear (direct_post). This protects the presented credential data in transit, including from intermediaries.
This is the default when using OpenID4VC V1 in Paradym, and it is required (per ISO 18013-7) when requesting mDoc credentials. You generally should not turn it off. See the requireResponseEncryption field on the create verification request endpoint and the verify credentials guide.
Issue using the authorization code flow
For issuance, use the authorization code flow backed by an authorization server rather than the pre-authorized code flow. The authorization code flow authenticates the user against your (or a third-party) identity provider as part of the issuance, binding the credential to an authenticated session and raising the assurance of the issued credential. See authorization servers and attribute providers for how to integrate this with Paradym.
Use a redirect-based same-device flow for presentations
For presentations, prefer the redirect-based same-device flow: the verification happens in the same browser/session that started it, and the wallet redirects the user-agent back to your application using a response_code that is bound to the original challenge.
A cross-device flow (for example scanning a QR code with a wallet on a different device) that does not use such a redirect binding is prone to session fixation / cross-device replay attacks: because there is no cryptographic binding between the device that started the flow and the device that presents the credential, an attacker can present a victim’s QR code (the authorization request) to their own wallet, or trick a victim into completing a flow the attacker initiated, and have the result land in the attacker’s session. The redirect-based same-device flow mitigates this by binding the result to the session that created the request: only the holder of the original challenge can retrieve the verification data.
Paradym’s OpenID4VP redirect flow, currently an experimental feature, implements exactly this binding. See that guide for how to opt in with redirectUri + challenge, including a worked example. To make it mandatory rather than optional, set openId4Vc.allowedFlows to ["sameDevice"] on the presentation template.
Cross-device flows are not inherently insecure, but they require a binding mechanism to be safe. We will soon add support for the W3C Digital Credentials API (DC API) , which provides a browser-mediated, origin-bound channel that makes cross-device (and same-device) flows secure without relying on a redirect. Until then, prefer the redirect-based same-device flow when assurance matters.
Relevant specifications
| Topic | Specification |
|---|---|
| High assurance profile | OpenID4VC High Assurance Interoperability Profile (HAIP) 1.0 |
| Issuance | OpenID for Verifiable Credential Issuance 1.0 |
| Presentation | OpenID for Verifiable Presentations 1.0 |
| Authorization code flow | OAuth 2.0 Authorization Framework (RFC 6749) |
| SD-JWT VC | SD-JWT-based Verifiable Credentials |
| mDoc | ISO/IEC 18013-5 and ISO/IEC 18013-7 (OpenID4VP profile) |
| Revocation | OAuth Token Status List |
| Cross-device (upcoming) | W3C Digital Credentials API |
Where to go next
- OpenID4VP redirect flow: the redirect-based same-device flow, end to end.
- Verify credentials: the full verification guide.
- Authorization servers: to issue using the authorization code flow.
- Trusted entities: to control which issuers you trust.
- Standards and protocols: the full list of standards Paradym supports.