OpenID4VP 验证方指南:接入 EUDI 钱包
OpenID4VP 验证方如何对接 EUDI 钱包:请求对象、DCQL 查询、响应模式、SD-JWT VC 与 mdoc 校验、欧盟法律中的 HAIP 规则、常见错误以及测试渠道。

要点
OpenID4VP(OpenID for Verifiable Presentations)是验证方向数字钱包请求凭证并取回已签名展示的协议。1.0 版于 2025年7月10日 成为 OpenID 最终规范,欧盟数字身份(EUDI)钱包将其用于远程展示。[2][3]
- 您发送一个带有 DCQL 查询的已签名请求,钱包返回 VP Token。
- 签发方签名、披露项、密钥绑定和撤销状态都由您自行验证。
- 对于 EUDI 钱包,欧盟法律另外规定了证书和注册规则。
网站或应用通过 OpenID4VP 请求钱包证明某人的某项信息,例如姓名或出生日期。验证方说明需要哪些凭证和声明,用户在钱包中批准,钱包返回一份展示,由验证方进行密码学校验。用规范本身的话说,它"定义了一种用于请求和展示凭证的协议"。[1]
本指南面向为 EUDI 钱包构建 OpenID4VP 验证方的开发者,内容包括:请求对象、DCQL、响应模式、设备流程、SD-JWT VC 和 mdoc 校验、欧盟法律中的 HAIP 规则、常见错误以及测试渠道。
用通俗的话讲 OpenID4VP
OpenID4VP 沿用 OAuth 2.0 授权请求的结构。验证方请求的响应类型为 vp_token,成功的响应必须包含承载展示内容的 vp_token 参数。[1] 不存在需要交换的授权码或访问令牌:数据直接随响应返回。
钱包对依赖方进行身份认证,检查其请求内容未超出注册范围,获取用户批准并对展示进行签名。随后由依赖方验证签发方签名、撤销状态和设备绑定。[3] 个人身份数据(PID)以 SD-JWT VC 和 ISO/IEC mdoc 两种格式签发,两者都使用加盐哈希,使用户可以只分享部分属性并隐藏其余属性。[5][3]
- 2025年7月10日最终规范OpenID4VP 1.0 获批。
- 2026年7月22日公布CIR 2026/1731(2026年7月15日通过)刊登于《欧盟官方公报》。
- 2026年7月23日ARF v3.0.0当前架构版本。
- 2026年12月24日钱包每个成员国至少一个。
- 2027年12月24日接受受监管的私营依赖方。
从最终规范到私营部门接受日期。[2][3][4][5]
OpenID4VP 验证方交互的工作原理
OpenID4VP 为 direct_post 响应模式发布了参考设计。在该模式下,钱包将响应直接 POST 到服务器端点,而不是通过浏览器传递。[1]
钱包核验验证方,用户同意
OpenID4VP 1.0 第 13.3 节中的 direct_post 参考设计(简化版)。[1]
- 每次请求生成一个 nonce,长度为“至少 16 个新生成的、密码学安全的随机字节”。
- 将响应端点返回的 request-id 作为
state发送给钱包。 - 钱包提交数据后,返回一个带有新
response_code的重定向 URI。 - 使用 transaction-id 和该 code 获取 VP Token,然后校验 nonce。
response_code 可防止会话固定攻击,即攻击者将您的请求转发到受害者的钱包。规范指出,它在跨设备场景下不起作用,并建议在该场景下采用额外机制。[1]
视频待发布:flow-eudi-openid4vp
来自 EUDI 钱包的一次 OpenID4VP 出示,从头到尾的完整流程。
OpenID4VP 请求对象与客户端标识符
client_id 以 Client Identifier Prefix 开头,该前缀告诉钱包如何对验证方进行身份验证。[1] 较大的请求通过引用传递:钱包从 request_uri 获取已签名的请求对象。对于二维码,规范建议使用 direct_post 搭配 request_uri,因为请求“可能无法放入二维码”。[1]
| 前缀 | 钱包如何对验证方进行身份验证 | 签名请求 |
|---|---|---|
redirect_uri | 标识符即重定向 URI 或响应 URI | 无法签名 |
x509_san_dns | 叶证书 SAN 中的 DNS 名称 | 必需 |
x509_hash | 叶证书的 SHA-256 哈希值 | 必需 |
decentralized_identifier | 来自 DID Document 的密钥 | 必需 |
verifier_attestation | 由钱包信任的签发方出具的 Attestation JWT | 必需 |
openid_federation | 联合信任链 | 依据 OpenID Federation |
客户端标识符前缀(Client Identifier Prefixes),OpenID4VP 1.0 第 5.9 节。[1]
对于 EUDI 验证方,前缀由欧盟法律指定:叶证书“用于 x509_hash Client Identifier Prefix 时,应为 ETSI TS 119 475 所规定的 RP 访问证书”,且 verifier_info 中的一个元素“应包含注册证书”。[5]
DCQL 查询:只请求您已注册的内容
数字凭证查询语言(DCQL)是一种 JSON 查询,用于指明您需要的凭证和声明。它包含一个必需的 credentials 数组和一个可选的 credential_sets 数组;每个凭证查询都需要一个 id、一个 format 和一个 meta 对象。[1] 规范中的 SD-JWT VC 示例:[1]
{ "credentials": [ { "id": "my_credential", "format": "dc+sd-jwt", "meta": { "vct_values": [ "https://credentials.example.com/identity_credential" ] }, "claims": [ {"path": ["last_name"]}, {"path": ["first_name"]}, {"path": ["address", "street_address"]} ] } ] }
对于 mdoc,格式为 mso_mdoc,meta 中包含一个 doctype_value。[1] 对于 PID,换成其类型和声明名称即可;PID 的必备属性为姓、名、出生日期、出生地和国籍。[7]
require_cryptographic_holder_binding默认为 true。请保持该设置:它使钱包返回密钥绑定证明。[1]trusted_authorities只是筛选钱包提供的内容。验证方“必须自行验证所收到出示内容的签发方是否可信”。[1]- 依赖方“不得要求用户提供”其已注册内容“以外的任何数据”,钱包会对此进行核查。[4][3]
OpenID4VP 响应模式
响应模式决定 VP Token 如何传回。vp_token 的默认模式为 fragment,即通过重定向 URI 的片段传回。[1]
| 响应模式 | VP Token 的传送去向 | 是否加密 |
|---|---|---|
fragment | 重定向 URI 片段,经由浏览器 | 否 |
direct_post | HTTP POST 至 response_uri | 否 |
direct_post.jwt | 以 HTTP POST 发送加密的 JWT | 是 |
dc_api | 经由 Digital Credentials API 传回 | 否 |
dc_api.jwt | 同上,加密 | 是 |
OpenID4VP 1.0 中的响应模式。[1]
使用 direct_post 时,必须提供 response_uri,且不得出现 redirect_uri,否则钱包将返回 invalid_request。[1] 例如,摩尔多瓦的 EVO Wallet 在文档中说明:在同设备流程中使用 OpenID4VP 1.0 和 direct_post.jwt,采用按 OpenID4VC HAIP 1.0 配置的 ISO/IEC 18013-5 mdoc,并使用 IETF Token Status List 进行撤销。[11]
同设备、跨设备与 Digital Credentials API
ARF 列出了所支持的远程组合:OpenID4VP 与基于重定向和自定义 URI 方案的传输机制相结合;OpenID4VP 或 ISO/IEC 18013-7 与 W3C Digital Credentials API 相结合;以及可选的 ISO/IEC 18013-7 与重定向和自定义 URI 方案相结合。[3]
同设备
自定义 URI 方案
- 浏览器将 openid4vp:// 交给操作系统
- 钱包在同一部手机上打开
ARF 4.4.3.1
跨设备
二维码
- 桌面端显示二维码供扫描
- 易受网络钓鱼和中继攻击
ARF 4.4.3.1
浏览器 API
Digital Credentials API
- 浏览器传递经验证的来源
- Chrome 141 中默认启用
OpenID4VP 附录 A
钱包接收 OpenID4VP 请求的三种方式。[3][1][10]
ARF 指出,自定义 URI 方案“不建议用于跨设备流程”,并将 Digital Credentials API 列为替代方案。[3] 通过该 API,钱包可获知经浏览器认证的验证方来源,“这对于抵御网络钓鱼十分重要”。[1] 该 W3C 规范目前仍为草案。[9] 用户在手机上看到的内容:
验证您的身份
本网站请求您的钱包提供您的信息。
1浏览器将 openid4vp:// URI 发送给操作系统。[3]
正在检查请求
钱包打开并连接到依赖方。
2钱包对依赖方进行认证,并核查其注册的内容。[3]
选择要共享的信息
- 姓氏已共享
- 出生日期已共享
- 地址未共享
共享
3用户批准共享这些属性。[3]
已收到信息
4钱包回传数据,并将用户送回原页面。[1]
逐步验证 SD-JWT VC 出示
一份 SD-JWT VC 出示包含发行方签名的 JWT、用户披露的信息,以及一个 Key Binding JWT。验证方"必须验证每一份可验证出示",并拒绝 nonce 不正确的出示。[1]
1验证发行方签名
该密钥可追溯至受信任的 PID 或证明提供方。
2检查每一项披露
每一项的哈希值都对应已签名载荷中的一个摘要。
3验证 Key Binding JWT
持有人密钥签名有效,nonce 和受众一致。
4检查撤销状态
读取发行方的状态列表。
所有检查均通过
使用已披露的属性
拒绝,并提供其他途径
验证方对一份 SD-JWT VC 出示执行的检查。[1][3]
发行方签名。ARF 将其列为依赖方检查的第一项。信任锚来自可信列表(ETSI TS 119 612)和可信实体列表(ETSI TS 119 602)。[3]
披露。已签名载荷中有一个由摘要组成的 _sd 数组。每一项披露由盐值、声明名称和值组成,例如 ["eluV5Og3gSNII8EYnsxA_A", "family_name", "Doe"]。[1]对每一项计算哈希值,并找到对应的摘要。没有匹配,就说明发行方并未签署该项。
Key Binding JWT。要求持有人绑定时,钱包"必须返回带有 Key Binding JWT 的 SD-JWT"。其 nonce 必须与您请求中的 nonce 相同,其 aud 必须与您的客户端标识符相同;如通过 Digital Credentials API 进行,则必须为加上 origin: 前缀的您的源。[1]规范中的示例:
{ "nonce": "n-0S6_WzA2Mj", "aud": "x509_san_dns:client.example.org", "iat": 1709838604, "sd_hash": "Dy-RYwZfaaoC3inJbLslgPvMp09bH-clYP_3qbRqtW4" }
撤销。依赖方核实提供方"未撤销该 PID 或证明"。[3]例如,摩尔多瓦的 EVO Wallet 为此记录了 IETF Token Status List 的使用方式。[11]
注意
PID 肖像照自 2028年8月11日起才成为强制项,因此在此之前不要计划将人脸与钱包肖像照进行比对。[5]
通过 ISO/IEC 18013-7 出示 mdoc 简介
对于 mdoc,VP Token 包含一个来自 ISO/IEC 18013-5、经 base64url 编码的 DeviceResponse,该响应“包含对 SessionTranscript 的签名或 MAC”,其中包括 OpenID4VP 交接(handover)结构。[1] 该交接结构将 mdoc 绑定到您的请求,就像 nonce 和 audience 绑定 SD-JWT VC 一样。
注意事项
欧盟法律对通过 Digital Credentials API 出示的 mdoc 适用“ISO/IEC 18013-7:2025 附件 C”。[5] ISO 将 18013-7 的 2024 版列为已撤销并被替代,因此请核实您的库实现的是哪个版本。[8]
我们的 SD-JWT VC 与 mdoc 对比说明了每种格式各自的适用场景。
HAIP 配置文件为 EUDI 验证方增加了哪些要求
高保证互操作性配置文件(HAIP)收窄了 OpenID4VP 的可选项。ARF 已要求在签发环节使用该配置文件,称其使用“是确保互操作性所必需的”。[3] 在出示环节,CIR 2026/1731 规定了“OpenID4VC-HAIP 配置文件”和“ISO/IEC-mdoc 配置文件”。[5]
| 要求 | 对您的验证方而言 | 来源 |
|---|---|---|
| 访问证书 | 使用 x509_hash 依赖方访问证书签名,ETSI TS 119 475 | CIR 2026/1731[5] |
| 注册证书 | 将其包含在 verifier_info 中 | CIR 2026/1731[5] |
| 注册 | 在您的设立地进行注册 | eIDAS 第 5b(1) 条[4] |
| 钱包检查 | 钱包单元自 2028年8月11日起才验证注册证书;这不是注册截止日期 | CIR 2026/1731[5] |
注册证书“描述依赖方的预期用途,并标明”其已注册的属性,注册条例自 2026年12月24日起适用。[6] 2028年8月11日这一日期仅涉及钱包端对该证书的检查,不涉及注册。[5] 德国的概括是:组织“针对该组织及其用例获得一份访问证书和注册证书”。[12] 我们的 EUDI 钱包依赖方指南完整介绍了注册流程。
构建 OpenID4VP 验证方时的常见错误
| 错误 | 解决方法 |
|---|---|
| 重复使用 nonce 或 nonce 过短 | 每个请求至少使用 16 个新生成的随机字节[1] |
| 未检查受众 | 将 aud 与您的客户端标识符(Client Identifier)或来源(origin)进行比对[1] |
| 请求未登记的数据 | 根据您的登记信息构建 DCQL 查询[4] |
| 跨设备使用自定义 URI 二维码 | 优先使用 Digital Credentials API[3] |
直接信任 trusted_authorities | 自行对照信任列表验证签发方[1] |
| 跳过吊销检查 | 每次都检查状态[3] |
使用 redirect_uri 前缀签名 | 该前缀无法签名;请使用 x509_hash[1][5] |
该钱包也是自愿使用的:对于不使用钱包的人,访问“不得以任何方式受到限制或处于不利地位”,因此您的验证方需要与另一种途径并存。[4]
测试资源
在对接各国钱包进行测试之前,先从参考软件和一致性测试入手。
- 在 conformance.eudi.dev 运行一致性测试。[3]
- 阅读 docs.eudi.dev 上的参考实现文档。这些是文档,不是测试。[3]
- 研究摩尔多瓦国家银行的演示验证方及其源代码。[13]
- 在依赖浏览器途径之前,先查阅 Digital Credentials API 草案。[9]
有关测试计划所依据的日期,请参阅 2026 年和 2027 年 EUDI 钱包截止日期。
Didit 如何协助 EUDI 钱包验证
Didit 即将支持接受 EUDI 钱包:该功能已列入我们的路线图,与 EUDI 钱包的时间表保持一致,并将纳入您目前使用的同一工作流程。在此期间,您现在就可以远程验证用户身份。
- 目前已有五种国家电子身份(eID)通过 数字身份钱包 在 Didit 中运行:MitID、BankID Sweden、Finnish Trust Network、Smart-ID 和 Mobile-ID。请参阅 eID 验证。
- 如果用户没有 eID,流程将回退到 证件验证,并结合 NFC 芯片读取、活体检测和人脸比对,按国家进行配置。一次完整的 KYC 检查费用为 $0.33。
- 反洗钱筛查 在同一流程中运行,费用为 $0.20。
您仍须履行依赖方义务。钱包文档 说明了如何按国家启用 eID。
Didit 提供
- 在同一工作流程中提供国家 eID 登录和证件验证途径
- 每次检查的证据
仍由您负责
- 您的钱包依赖方注册
- 开户决策与您的政策
要点
- OpenID4VP 1.0 自2025年7月10日起成为 OpenID 正式规范。
- 发送受您注册范围限制的 DCQL 查询,并附上新生成的 nonce。
- 验证签发方签名、每一项披露、Key Binding JWT 以及吊销情况。
- EUDI 验证方使用
x509_hashRP 访问证书签名。 - 适用范围内的私营依赖方须在2027年12月24日前接受该钱包。
常见问题
什么是 OpenID4VP?
OpenID for Verifiable Presentations 是一种用于请求和出示凭证的协议。钱包在 VP Token 中返回已签名的出示内容,无需交换授权码或访问令牌。1.0 版于 2025年7月10日 成为 OpenID 正式规范(Final Specification)。[1][2]
EUDI 钱包使用 OpenID4VP 吗?
是的,用于远程出示,与 ISO/IEC 18013-7 并行使用。欧盟法律规定了 OpenID4VC-HAIP 配置文件和 ISO/IEC-mdoc 配置文件。[3][5]
什么是 DCQL?
Digital Credentials Query Language(数字凭证查询语言)是一种 JSON 查询,列明验证方需要的凭证和声明。钱包返回与之匹配的出示内容。对于 EUDI 钱包,只请求您已注册的属性。[1][4]
EUDI 验证方应使用哪种响应模式?
服务器端验证方使用 direct_post 或加密的 direct_post.jwt。通过 Digital Credentials API 时,模式为 dc_api 和 dc_api.jwt。[1]
如何验证 Key Binding JWT?
使用凭证中绑定的密钥验证其签名,然后根据您的请求核对其 nonce 和 audience。通过 Digital Credentials API 时,audience 为您的 origin(来源)。[1]
EUDI 验证方使用哪种客户端标识符前缀?
x509_hash,配合符合 ETSI TS 119 475 的 RP 访问证书。注册证书放在 verifier_info 中。[5]
可以跨设备使用二维码吗?
可以,但由于网络钓鱼和中继攻击风险,ARF 不建议跨设备使用自定义 URI 方案。它指出 Digital Credentials API 是替代方案。[3]
可以与钱包中的肖像照进行人脸比对吗?
目前尚不可靠。肖像照自 2028年8月11日 起才成为 PID 强制数据。[5]
在哪里可以测试 OpenID4VP 验证方?
在 conformance.eudi.dev 运行一致性测试,并在 docs.eudi.dev 阅读参考实现文档。摩尔多瓦中央银行也发布了一个附带源代码的演示验证方。[3][13]
参考来源
- OpenID for Verifiable Presentations 1.0,OpenID Foundation,最终规范。
- OpenID for Verifiable Presentations 1.0 最终规范获批准,OpenID Foundation,2025年7月10日。
- 架构与参考框架(Architecture and Reference Framework)v3.0.0,GitHub 上的 eu-digital-identity-wallet,2026年7月23日发布。
- 条例 (EU) 2024/1183(eIDAS 2),EUR-Lex,2024年4月30日《欧盟官方公报》。
- 欧盟委员会实施条例 (EU) 2026/1731,EUR-Lex,2026年7月22日《欧盟官方公报》。
- 关于钱包依赖方注册的欧盟委员会实施条例 (EU) 2025/848,EUR-Lex,2025年5月7日《欧盟官方公报》。
- 关于个人身份识别数据的欧盟委员会实施条例 (EU) 2024/2977,EUR-Lex,2024年12月4日《欧盟官方公报》。
- ISO/IEC 18013-7,ISO 标准页面。
- Digital Credentials,W3C 草案。
- Digital Credentials API 已正式发布,Chrome for Developers。
- EVO Wallet 开发者指南,摩尔多瓦政府,egov4dev。
- EUDI 钱包常见问题,eudi-wallet.gov.de。
- BNM 演示验证方,摩尔多瓦政府,egov4dev。
OpenID4VP 是开发者接触最多的 EUDI 钱包组成部分,而且已经足够稳定,可以据此进行开发。请在 EUDI 钱包解决方案页面了解 Didit 如何处理钱包接受,并在我们的 eIDAS 2 概览中了解更全面的情况。