| Internet-Draft | Credential to OIDC Bridge | August 2026 |
| Svensson, et al. | Expires 25 February 2027 | [Page] |
This document defines a mechanism for conveying digital credential claims via OpenID Connect (OIDC). It specifies how an OpenID Provider (OP) that collects credentials from a wallet can expose those claims to Relying Parties as standard OIDC claims, enabling existing OIDC deployments to consume digital credentials without implementing any wallet-facing presentation protocol.¶
This note is to be removed before publishing as an RFC.¶
Source for this draft and an issue tracker can be found at https://github.com/masv3971/rfc_credential_oidc_bridge.¶
This Internet-Draft is submitted in full conformance with the provisions of BCP 78 and BCP 79.¶
Internet-Drafts are working documents of the Internet Engineering Task Force (IETF). Note that other groups may also distribute working documents as Internet-Drafts. The list of current Internet-Drafts is at https://datatracker.ietf.org/drafts/current/.¶
Internet-Drafts are draft documents valid for a maximum of six months and may be updated, replaced, or obsoleted by other documents at any time. It is inappropriate to use Internet-Drafts as reference material or to cite them other than as "work in progress."¶
This Internet-Draft will expire on 25 February 2027.¶
Copyright (c) 2026 IETF Trust and the persons identified as the document authors. All rights reserved.¶
This document is subject to BCP 78 and the IETF Trust's Legal Provisions Relating to IETF Documents (https://trustee.ietf.org/license-info) in effect on the date of publication of this document. Please review these documents carefully, as they describe your rights and restrictions with respect to this document. Code Components extracted from this document must include Revised BSD License text as described in Section 4.e of the Trust Legal Provisions and are provided without warranty as described in the Revised BSD License.¶
Digital credential wallets can present verified claims to verifiers using protocols such as OpenID for Verifiable Presentations (OpenID4VP) [OpenID4VP] or DIDComm. However, many existing services rely on OpenID Connect (OIDC) [OpenID.Core] for authentication and attribute retrieval, and implementing a wallet-facing presentation protocol represents a significant barrier for these Relying Parties.¶
This document specifies how an OP, acting as a bridge, can collect credentials from a wallet using any suitable presentation protocol and expose the resulting claims in standard OIDC ID Tokens and UserInfo responses. The Relying Party interacts with a normal OIDC flow and receives credential data in the "presented_credentials" claim without needing any knowledge of the underlying presentation protocol.¶
This specification is intended to complement, not compete with, work produced by the OpenID Foundation. Implementers are encouraged to follow developments in the OpenID Foundation's Digital Credentials Protocols working group.¶
The following diagram illustrates the high-level interaction between the participants:¶
+--------+ +------------------+ +----------+ | | 1. OIDC AuthN | | 2. Present | | | RP | -------------> | OP (Bridge) | -----------> | Wallet | | | | | <----------- | | | | | | 3. Response | | | | | | +----------+ | | | 4. Verify & | | | 5. ID Token | extract claims| | | <------------- | | +--------+ +------------------+¶
The presentation protocol (steps 2-3) is out of scope for this specification. The OP MAY use OpenID4VP, DIDComm, or any other suitable mechanism.¶
The steps are:¶
The RP sends an OIDC Authentication Request to the OP, including credential type scopes.¶
The OP initiates a credential presentation request to the user's wallet.¶
The wallet responds with the disclosed credentials.¶
The OP verifies the credentials and extracts claims.¶
The OP returns an ID Token and/or UserInfo response containing the "presented_credentials" claim.¶
The key words "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL NOT", "SHOULD", "SHOULD NOT", "RECOMMENDED", "NOT RECOMMENDED", "MAY", and "OPTIONAL" in this document are to be interpreted as described in BCP 14 [RFC2119] [RFC8174] when, and only when, they appear in all capitals, as shown here.¶
The following terms are used throughout this document:¶
An OIDC client that consumes claims from the OP. In this specification, the RP receives credential claims without directly interacting with the wallet.¶
The authorization server that acts as a bridge between the wallet and the RP. The OP collects credentials from the wallet using a presentation protocol and exposes the resulting claims via standard OIDC mechanisms.¶
A user-controlled application that holds digital credentials and can present them to a verifier upon request.¶
A JSON object within the "presented_credentials" array where each key is a credential type scope and each value is an array of Credential Entry objects.¶
A JSON object representing a single credential presented during the presentation flow, containing metadata and disclosed claims.¶
An RP that wishes to receive credential data via this bridge MUST
include credential type scopes in the OIDC Authentication Request
(e.g., scope=openid ehic pda1). This specification defines two
request modes:¶
Scope-based (REQUIRED to support): the RP includes only credential type scopes. The OP applies a pre-registered query per scope (see Section 5.4) and returns the claims configured for that credential type. Every OP that implements this specification MUST support this mode.¶
DCQL-based (OPTIONAL): the RP additionally supplies a "dcql_query" member inside the OIDC "claims" request parameter. The value is a DCQL query [OpenID4VP] constrained to the profile defined in Section 4.1.2.¶
Deployments operating under trust frameworks that require pre-
registered credential queries (for example, EUDI and the Swiss
Trust Framework) MUST NOT advertise "dcql_query_supported" as
true. An RP that sends a "dcql_query" to such an OP will
receive an "invalid_request" error per Section 4.1.2.
An RP MUST consult the OP's discovery metadata (see
Section 5.2) to determine whether the DCQL-based mode is
supported before including a "dcql_query".¶
Scopes identify which credentials to collect; the "dcql_query" member, when present, refines how they are collected. If only scopes are present, the OP applies its pre-registered mapping for each scope.¶
The following is a non-normative example of a scope-based request (no "claims" parameter). The RP requests EHIC and PDA1 credentials using the OP's pre-registered mapping:¶
GET /authorize? response_type=code &scope=openid ehic pda1 &client_id=https://rp.example.org &redirect_uri=https://rp.example.org/cb &nonce=n-0S6_WzA2Mj HTTP/1.1¶
The requested scopes directly correlate to the keys used in the Credential Set returned by the OP. For example, if the RP requests scopes "ehic" and "pda1", the resulting Credential Set contains "ehic" and "pda1" entries.¶
In scope-based mode the RP cannot express selective disclosure, value constraints, or issuer restrictions on a per-request basis; the OP applies its own policy. RPs that need such control MAY use the DCQL-based mode (Section 4.1.2) where supported by the OP.¶
An RP MAY supply a "dcql_query" member inside the OIDC "claims" request parameter as permitted by Section 5.5.1 of [OpenID.Core]. The "dcql_query" value MUST be a DCQL query object as defined in Section 6 of [OpenID4VP], restricted to the profile defined in this section.¶
An OP that supports the DCQL-based mode MUST advertise this in its discovery metadata via "dcql_query_supported" (see Section 5.2). If the OP does not support the DCQL-based mode and the RP supplies a "dcql_query", the OP MUST return an OIDC error response with error code "invalid_request".¶
The "dcql_query" value is a DCQL query object as defined in
Section 6 of [OpenID4VP]. All member definitions, required and
optional fields, and format-specific rules (e.g., for the "meta"
object of dc+sd-jwt and mso_mdoc) are inherited from that
section and are not restated here.¶
This profile applies the following additional restrictions:¶
The DCQL "claim_sets" member MUST NOT be used; express claim alternation via multiple Credential Queries linked from "credential_sets".¶
Each Credential Query MUST identify a credential type (via "format" and the format-specific type identifier in "meta") that matches an entry in "credential_presentations_supported" whose scope value is present in the authorization request. Otherwise the OP MUST return "invalid_request".¶
Credential Query "id" values are opaque to the OP (per Section 6 of [OpenID4VP]) and are used only as response keys and as references from "credential_sets".¶
When "claims" is omitted, the OP applies the pre-registered claim set of the matched entry.¶
The "credential_sets" member expresses combinatorial logic over
Credential Queries as defined in Section 6.3 of [OpenID4VP].
Each Credential Set entry contains an "options" array listing
alternative AND-groups of Credential Query "id"s, plus an OPTIONAL
"id" and OPTIONAL "required" boolean (default true). If
"credential_sets" is present, the OP MUST evaluate the alternation
per Section 6.3 of [OpenID4VP] and return, for each satisfied
Credential Set, one Credential Set object within the
"presented_credentials" claim (see Section 5.1.1)
whose members are the Credential Queries in the matched AND-group.
The OPTIONAL "id" of the Credential Set entry MAY be echoed by the
OP in the response to help the RP identify which alternative was
satisfied (see Section 5.1.1).¶
If "credential_sets" is absent, the OP treats all Credential Queries as required, matching the DCQL default behaviour.¶
Trusted authority handling:¶
When a Credential Query includes "trusted_authorities", the OP MUST only accept a credential for that query if it chains to at least one of the listed authorities. Credentials that do not chain to any listed authority MUST be treated as not satisfying the query.¶
If "trusted_authorities" is absent, the OP applies its own issuer policy.¶
Security requirements for dereferencing external trust list references (e.g., "etsi_tl", "openid_federation") are given in Section 7.4.¶
The following is a non-normative example requesting a PID from a specific pair of trusted authorities using the OpenID Federation authority type:¶
{
"id_token": {
"dcql_query": {
"credentials": [
{
"id": "pid",
"format": "dc+sd-jwt",
"meta": {
"vct_values": ["urn:eu.europa.ec.eudi:pid:1"]
},
"claims": [
{"path": ["family_name"]},
{"path": ["given_name"]},
{"path": ["birth_date"]}
],
"trusted_authorities": [
{
"type": "openid_federation",
"values": [
"https://pid.example.gov.se",
"https://pid.example.gov.no"
]
}
]
}
]
}
}
}
¶
The following is a non-normative example using an ETSI Trust List to accept PID and EHIC credentials from any issuer recognised by the list, without enumerating each issuer individually:¶
{
"id_token": {
"dcql_query": {
"credentials": [
{
"id": "pid",
"format": "dc+sd-jwt",
"meta": {"vct_values": ["urn:eu.europa.ec.eudi:pid:1"]},
"claims": [
{"path": ["family_name"]},
{"path": ["birth_date"]}
],
"trusted_authorities": [
{
"type": "etsi_tl",
"values": ["https://trust.eu.example.org/tsl.xml"]
}
]
},
{
"id": "ehic",
"format": "dc+sd-jwt",
"meta": {"vct_values": ["urn:eu.europa.ec.eudi:ehic:1"]},
"claims": [
{"path": ["ehic_number"]}
],
"trusted_authorities": [
{
"type": "etsi_tl",
"values": ["https://trust.eu.example.org/tsl.xml"]
}
]
}
]
}
}
}
¶
The following is a non-normative example expressing "PID AND EHIC together":¶
{
"id_token": {
"dcql_query": {
"credentials": [
{
"id": "pid",
"format": "dc+sd-jwt",
"meta": {"vct_values": ["urn:eu.europa.ec.eudi:pid:1"]},
"claims": [{"path": ["family_name"]}]
},
{
"id": "ehic",
"format": "dc+sd-jwt",
"meta": {"vct_values": ["urn:eu.europa.ec.eudi:ehic:1"]},
"claims": [{"path": ["ehic_number"]}]
}
],
"credential_sets": [
{
"id": "pid_and_ehic",
"options": [["pid", "ehic"]]
}
]
}
}
}
¶
The following is a non-normative example expressing "PID OR EHIC" using two alternatives. Only the AND-group that was satisfied appears in the corresponding Credential Set in the response:¶
{
"id_token": {
"dcql_query": {
"credentials": [
{
"id": "pid",
"format": "dc+sd-jwt",
"meta": {"vct_values": ["urn:eu.europa.ec.eudi:pid:1"]},
"claims": [{"path": ["family_name"]}]
},
{
"id": "ehic",
"format": "dc+sd-jwt",
"meta": {"vct_values": ["urn:eu.europa.ec.eudi:ehic:1"]},
"claims": [{"path": ["ehic_number"]}]
}
],
"credential_sets": [
{
"id": "pid_or_ehic",
"options": [["pid"], ["ehic"]]
}
]
}
}
}
¶
The following is a non-normative example expressing "PID required, EHIC nice-to-have" using two Credential Sets, one required and one optional:¶
{
"id_token": {
"dcql_query": {
"credentials": [
{
"id": "pid",
"format": "dc+sd-jwt",
"meta": {"vct_values": ["urn:eu.europa.ec.eudi:pid:1"]},
"claims": [{"path": ["family_name"]}]
},
{
"id": "ehic",
"format": "dc+sd-jwt",
"meta": {"vct_values": ["urn:eu.europa.ec.eudi:ehic:1"]},
"claims": [{"path": ["ehic_number"]}]
}
],
"credential_sets": [
{"id": "pid_required", "options": [["pid"]], "required": true},
{"id": "ehic_optional", "options": [["ehic"]], "required": false}
]
}
}
}
¶
The following is a non-normative example applying a value constraint on "age_over_18":¶
{
"id_token": {
"dcql_query": {
"credentials": [
{
"id": "pid",
"format": "dc+sd-jwt",
"meta": {"vct_values": ["urn:eu.europa.ec.eudi:pid:1"]},
"claims": [
{"path": ["family_name"]},
{"path": ["age_over_18"], "values": [true]}
]
}
]
}
}
}
¶
The following is a non-normative example requesting nested claims from a PID credential:¶
{
"id_token": {
"dcql_query": {
"credentials": [
{
"id": "pid",
"format": "dc+sd-jwt",
"meta": {"vct_values": ["urn:eu.europa.ec.eudi:pid:1"]},
"claims": [
{"path": ["family_name"]},
{"path": ["address", "street_address"]},
{"path": ["address", "country"], "values": ["SE"]}
]
}
]
}
}
}
¶
If the wallet presents multiple credentials matching a single Credential Query (e.g., two EHICs for different family members), the OP returns all of them in the corresponding array within the Credential Set. The RP is responsible for selecting the appropriate credential by inspecting the returned claims (for example, matching on name or date of birth against the authenticated user's identity).¶
The "presented_credentials" claim structure is defined in Section 5.1. The RP MUST parse the claim according to that definition.¶
Credential authenticity, holder binding, revocation status, and enforcement of any DCQL constraints supplied by the RP are the responsibility of the OP (see Section 4.3); the RP does not re-verify the credential. The "verification" object and other validation-related metadata returned by the OP (see Section 5.1.2) are informational: the RP MAY use them as inputs to its own business logic, policy engine, or audit records. How the RP uses that metadata is a matter of local policy and out of scope for this specification, except where noted for "verification.crit" in Section 5.1.2.¶
Specifically, the RP MUST:¶
Check for the presence of the "presented_credentials" claim. If the claim was requested as essential and is absent, the RP SHOULD treat the authentication as failed.¶
Parse the "presented_credentials" array and extract the Credential Set objects relevant to its use case.¶
Not assume that all requested scopes will be present in the response; the user may have declined to present certain credentials.¶
Except for members listed in "verification.crit", ignore unrecognised credential keys and unrecognised members within Credential Entry objects.¶
The RP places trust in the OP to have correctly verified the presented credentials. The RP does not interact with the wallet or credential issuer directly. The trust relationship between the RP and the OP is established through standard OIDC mechanisms (client registration, token validation, TLS).¶
The bridge architecture shifts credential verification responsibility from the RP to the OP. This has implications for liability that deployments MUST consider.¶
The OP is the sole party that interacts with the wallet and verifies credential authenticity, revocation status, and holder binding. The RP relies entirely on the OP's assertion that the credential claims are valid. If the OP incorrectly accepts a forged, expired, or revoked credential, the RP has no independent means of detecting this.¶
Deployments SHOULD establish clear agreements between the OP operator and RPs that address:¶
The OP's obligations regarding credential verification (e.g., which trust frameworks it enforces, whether it checks revocation).¶
Liability allocation when the OP accepts a credential that turns out to be invalid or fraudulent.¶
The OP's obligations to communicate changes to its verification policy that may affect RP authorization decisions.¶
Audit and logging requirements that allow after-the-fact review of verification decisions.¶
The "verification" metadata in the Credential Entry (Section 5.1.2) provides a technical mechanism for the OP to communicate verification details to the RP. However, the "verification" object does not constitute a legal guarantee. RPs operating in regulated environments (e.g., healthcare, finance) SHOULD require contractual assurances from the OP in addition to the technical signals provided by this specification.¶
The following is a non-normative example of an OIDC ID Token containing the "presented_credentials" claim with a credential set containing two credentials:¶
{
"iss": "https://issuer.example.org",
"sub": "user@example.org",
"iat": 1722772800,
"exp": 1722859200,
"presented_credentials": [
{
"ehic": [
{
"type": ["https://credential.example.org/ehic/1.0"],
"issuer": "https://svs.example.se",
"valid_from": 1709251200,
"valid_until": 1740787200,
"verified_at": 1722772700,
"verification": {
"trust_status": "not_checked",
"holder_binding": "key_binding"
},
"claims": {
"name": "John Doe",
"dob": "1990-01-01",
"ehic_number": "1234567890"
}
}
],
"pda1": [
{
"type": ["https://credential.example.org/pda1/1.0"],
"issuer": "https://tax.example.se",
"valid_from": 1709251200,
"valid_until": 1740787200,
"verified_at": 1722772700,
"verification": {
"trust_status": "not_checked",
"holder_binding": "key_binding"
},
"claims": {
"name": "John Doe",
"dob": "1990-01-01",
"pda1_number": "0987654321",
"employer": {
"name": "Example Corp AB",
"country": "SE"
}
}
}
]
}
]
}
¶
The "presented_credentials" claim is a top-level JSON array included in the OIDC ID Token or UserInfo response. It contains credential data obtained via a credential presentation flow (e.g., OpenID4VP, DIDComm), re-packaged for consumption by OIDC Relying Parties.¶
The array contains one or more Credential Set objects. Each Credential Set is a JSON object whose members are either credential entries (each key a scope value in scope-based mode, or a DCQL Credential Query "id" in DCQL-based mode, with the value being a JSON array of Credential Entry objects as defined in Section 5.1.2), or the reserved member described below.¶
The following reserved member MAY be present at the top level of a Credential Set:¶
OPTIONAL string. When the RP used the DCQL-based mode
(Section 4.1.2) and supplied a "credential_sets" entry
with an "id", the OP MAY echo that "id" here to allow the RP to
identify which Credential Set was satisfied. The value is
chosen by the RP and treated as opaque by the OP; for example,
an RP that asked for "PID or EHIC" via a "credential_sets" entry
with "id": "pid_or_ehic" receives the same string back on the
corresponding Credential Set in the response. The reserved
name "id" MUST NOT be used as a credential type scope value
(i.e., as a key in "credential_presentations_supported") nor as
a DCQL Credential Query identifier.¶
Within a Credential Set:¶
Each non-reserved key MUST be unique.¶
Each non-reserved value (array) MUST contain at least one Credential Entry. Multiple entries indicate the wallet presented more than one credential of that type.¶
The outer array MUST contain at least one Credential Set. In most deployments a single set is returned; multiple sets are possible when the RP requested alternatives via "credential_sets" in the DCQL-based mode (see Section 4.1). In that case the OP MUST return one Credential Set object per satisfied DCQL Credential Set entry, in the same order as they appeared in the request.¶
Additional members within a Credential Set MAY be present. Implementations that do not recognise additional members MUST ignore them.¶
Each Credential Entry object represents a single credential presented during the presentation flow. It MUST contain the following members:¶
A non-empty JSON array of strings identifying the credential type. The array contents are credential-format specific:¶
For SD-JWT VC credentials the array contains a single element: the Verifiable Credential Type (vct).¶
For ISO mdoc credentials the array contains a single element: the docType.¶
For W3C Verifiable Credentials the array is the credential's "type" array, preserving the order in the credential.¶
For other formats the array contains the type identifier(s) that the credential format defines, preserving any ordering defined by that format. Single-value formats produce a one-element array.¶
The OP MUST set this field based on the presented credential.¶
A JSON object [RFC8259] containing the disclosed claims from the credential. Each key is a claim name and each value is the claim value. Claim names are determined by the credential type and MUST be strings. Claim values MAY be any valid JSON type.¶
It MAY contain the following additional members:¶
A string identifying the entity that issued the credential. For SD-JWT VC credentials this is the "iss" claim value, for mdoc credentials it is the issuing authority identifier. The OP SHOULD populate this field to allow the RP to make issuer-aware authorization decisions.¶
A string identifying the credential-format-specific namespace to which the disclosed claims belong. This member is intended for formats that scope claims by namespace, such as ISO mdoc, where its value corresponds to the mdoc NameSpace identifier. For credential formats that do not use namespaces this member MUST NOT be present.¶
A NumericDate (as defined in [RFC7519]) indicating when the credential became valid (i.e., the issuance or activation date).¶
A NumericDate indicating when the credential expires. The OP MAY include credentials whose "valid_until" is in the past at the time of presentation; in that case the OP MUST set the "trust_status" member of the "verification" object to "expired" (see Section 8.3) so that the RP can act on the signal. Whether to accept an expired credential is outside the scope of this specification and is governed by deployment policy, the applicable trust framework, and any agreements between the OP and the RP.¶
A NumericDate indicating when the OP verified the credential during the presentation flow. This allows the RP to assess the freshness of the verification relative to its own requirements.¶
A JSON object providing metadata about the verification the OP performed on the credential. The OP MUST include the "verification" object in every Credential Entry. If the OP did not perform a trust-status check, it MUST set "trust_status" to "not_checked" (see Section 8.3); other members of "verification" MAY be omitted when the corresponding information is unavailable. This object MAY contain the following members:¶
A string describing the mechanism used to verify that the presenter is the legitimate holder of the credential. Values are taken from the "Credential Holder Binding Methods" registry defined in Section 8.4.¶
A string describing the OP's assessment of the credential's trust status at the time of verification. Values are taken from the "Credential Trust Status Values" registry defined in Section 8.3. If the OP did not perform a trust-status check, the OP MUST set this member to "not_checked" rather than omitting it. If the OP performed a check but the authoritative source returned no conclusive answer, the OP MUST set this member to "unknown".¶
A JSON object echoing selected verified protected-header parameters from the underlying credential (e.g., JOSE "alg", "kid", "x5c", or COSE protected headers for mdoc). The OP MUST populate this member exclusively from headers that were covered by the credential's signature verification and MUST NOT include unverified data. The set of parameters included is a deployment decision.¶
A JSON array of non-empty strings, each naming another member of the same "verification" object that the RP MUST understand to accept the credential. Semantics are modelled after the "crit" Header Parameter of Section 4.1.11 of RFC 7515. If the RP does not recognise every member listed in "crit", or does not understand the semantics assigned to the listed member's value, the RP MUST treat the credential as not satisfying the request. Values listed in "crit" MUST also appear as members of the "verification" object; the string "crit" itself MUST NOT appear in the array. This mechanism allows the OP to ensure that safety-critical signals (e.g., a "trust_status" of "suspended") cannot be silently ignored.¶
Additional members within the "verification" object MAY be present. Unless listed in "crit", implementations that do not recognise additional members MUST ignore them.¶
The following is a non-normative example of a Credential Entry with nested claims and an extended "verification" object, as might appear in a PID credential whose trust status the OP wants the RP to acknowledge:¶
{
"type": ["urn:eu.europa.ec.eudi:pid:1"],
"issuer": "https://pid.example.gov.se",
"valid_from": 1709251200,
"valid_until": 1740787200,
"verified_at": 1722772700,
"verification": {
"holder_binding": "key_binding",
"trust_status": "suspended",
"protected_headers": {
"alg": "ES256",
"kid": "pid-signer-2026"
},
"crit": ["trust_status"]
},
"claims": {
"family_name": "Doe",
"given_name": "John",
"birth_date": "1990-01-01",
"address": {
"street_address": "123 Main St",
"locality": "Stockholm",
"postal_code": "11122",
"country": "SE"
},
"age_over_18": true,
"nationalities": [
"SE",
"NO"
]
}
}
¶
The following is a non-normative example of a Credential Entry for a W3C Verifiable Credential where "type" is an array:¶
{
"type": ["VerifiableCredential", "UniversityDegreeCredential"],
"issuer": "https://university.example.edu",
"verified_at": 1722772700,
"verification": {
"trust_status": "not_checked",
"holder_binding": "key_binding"
},
"claims": {
"degree": {
"type": "BachelorDegree",
"name": "Bachelor of Science and Arts"
}
}
}
¶
Additional members MAY be present. Implementations that do not recognise additional members MUST ignore them.¶
An OP that supports this bridge mechanism MUST include "presented_credentials" in the "claims_supported" list in its OpenID Connect Discovery [OpenID.Discovery] metadata document.¶
The OP MUST include a "credential_presentations_supported" member in its discovery metadata. This is a JSON object where each key is a scope value that the RP can use in the authorization request, and each value is an object describing the credential type configuration. Each configuration object MUST contain at minimum:¶
A string identifying the credential format (e.g., "dc+sd-jwt", "mso_mdoc").¶
A string identifying the credential type. For SD-JWT VC credentials this is the vct value; for mdoc credentials this is the docType.¶
The OP uses this metadata to translate the RP's scope request into the correct credential query (e.g., a DCQL query with the appropriate "vct_values" or "doctype_value") toward the wallet. The Credential Entry "type" array in the response MUST be populated from the presented credential itself and MUST contain the "type" value declared in this mapping.¶
An OP that additionally supports the DCQL-based request mode
(Section 4.1.2) MUST include a JSON boolean member
"dcql_query_supported" in its discovery metadata with the value
true. An OP that does not support the DCQL-based mode MAY omit
this member or set it to false.¶
The following is a non-normative example of an RP discovering the OP's supported credential types:¶
GET /.well-known/openid-configuration HTTP/1.1 Host: op.example.org¶
HTTP/1.1 200 OK
Content-Type: application/json
{
"issuer": "https://op.example.org",
"authorization_endpoint": "https://op.example.org/authorize",
"token_endpoint": "https://op.example.org/token",
"userinfo_endpoint": "https://op.example.org/userinfo",
"jwks_uri": "https://op.example.org/jwks.json",
"credential_presentations_supported": {
"ehic": {
"format": "dc+sd-jwt",
"type": "urn:eu.europa.ec.eudi:ehic:1"
},
"pda1": {
"format": "dc+sd-jwt",
"type": "urn:eu.europa.ec.eudi:pda1:1"
}
}
}
¶
When the OP receives an OIDC Authentication Request that includes credential type scopes (and optionally a "dcql_query" member inside the OIDC "claims" request parameter for fine-grained control), it MUST:¶
Validate that each credential type scope corresponds to a key in the OP's "credential_presentations_supported" metadata. The OP MUST ignore any credential type scope that is not present in its metadata. If none of the requested credential scopes are supported, the OP MUST return an OIDC error response.¶
If the request includes a "dcql_query" member, validate it against the profile defined in Section 4.1.2. If the OP does not support the DCQL-based mode, or the query does not conform to the profile, the OP MUST return an OIDC error response with error code "invalid_request".¶
Initiate a credential presentation request to the user's wallet for the supported credential types, using the presentation protocol supported by the deployment. When the RP supplied a "dcql_query", the OP SHOULD translate it into the corresponding presentation-protocol query (see Appendix A for the DCQL binding).¶
Verify the presented credentials according to the applicable trust framework, including any "trusted_authorities" constraints from the RP's "dcql_query".¶
Extract the disclosed claims from each verified credential.¶
Construct the "presented_credentials" object as defined in Section 5.1.1.¶
Include the "presented_credentials" claim in the ID Token, the UserInfo response, or both, depending on the OP's policy and the size considerations described in Section 6.1.¶
Common presentation protocols include OpenID4VP [OpenID4VP] and DIDComm Present Proof. The choice of protocol is a deployment decision and does not affect the "presented_credentials" format returned to the RP.¶
This section describes the protocol-agnostic mapping between the OIDC-level request the RP sends to the OP and the credential data the OP returns. Concrete bindings to specific presentation protocols are given in the appendices; the DCQL binding used with OpenID4VP is defined in Appendix A, and a placeholder for a future DIDComm binding appears in Appendix B.¶
The OP uses the "credential_presentations_supported" discovery metadata to translate scopes into credential queries. For each credential type scope in the authorization request, the OP looks up the corresponding key in "credential_presentations_supported" and uses the "format" and "type" values to construct the presentation-protocol query. The same key is used both to identify the credential in the query toward the wallet and as the key in the "presented_credentials" response.¶
The binding is:¶
The key in "credential_presentations_supported" (e.g., "ehic") is the scope value the RP includes in the authorization request, and MUST also be used as the Credential Query identifier in the presentation-protocol query.¶
The OP MUST use the "format" and "type" from the configuration entry to populate the presentation-protocol query's format and type-identifier parameters.¶
The OP MUST use this same value as the key in the "presented_credentials" response object. For example, if the RP requested scope "ehic", the resulting Credential Set entry MUST be keyed as "ehic".¶
When the RP additionally supplied a "dcql_query" in the OIDC "claims" request parameter (Section 4.1.2), the OP MUST use the RP-chosen Credential Query "id" values as the keys in the "presented_credentials" response. Correlation to "credential_presentations_supported" is by credential type, per Section 4.1.2.¶
Response construction rules:¶
The OP MUST NOT include claims that were not disclosed by the wallet.¶
The OP MUST NOT modify claim values during the mapping.¶
When the RP used the DCQL-based mode and specified a non-empty "claims" array for a Credential Query, the OP MUST include only the requested claims in the corresponding Credential Entry's "claims" object. Even if the wallet discloses additional claims (for example, because the credential format does not support selective disclosure), the OP MUST NOT relay unrequested claims to the RP. This ensures data minimization regardless of the underlying credential format's selective disclosure capabilities.¶
When the RP used scope-based mode, or the RP's Credential Query omitted "claims", the OP includes the claim set configured for that credential type by deployment policy.¶
Constraint enforcement rules:¶
If a claim query in the RP's "dcql_query" specifies a "values" array and the disclosed claim value does not match any entry (using the matching rules in Appendix C), the credential MUST be treated as not satisfying the query.¶
If the RP's "dcql_query" specifies "trusted_authorities" for a Credential Query and the presented credential does not chain to at least one listed authority, the credential MUST be treated as not satisfying the query. Security requirements for dereferencing external trust material are given in Section 7.4.¶
If the RP's "dcql_query" includes "credential_sets", the OP MUST evaluate the alternation per Section 6.3 of [OpenID4VP]. If no required Credential Set can be satisfied, the OP MUST return an OIDC error response (e.g., "access_denied").¶
Applicability of RP-supplied constraints:¶
In scope-based mode the RP cannot express selective-disclosure, value, or issuer constraints on a per-request basis; the OP applies its own policy.¶
In DCQL-based mode the RP can express selective disclosure via "path", value constraints via "values", and issuer or authority constraints via "trusted_authorities", within the profile defined in Section 4.1.2.¶
Constraints not expressible in this profile (for example, issuance date filters or compound field requirements) remain deployment policy. The OP SHOULD document such policies so that RPs can anticipate the resulting behaviour.¶
The structure of the "presented_credentials" claim MUST be independent of the credential presentation protocol used between the OP and the wallet. Whether the OP collected credentials via OpenID4VP, DIDComm, or any other mechanism, the resulting claim format MUST conform to this specification. The RP MUST NOT need to be aware of which presentation protocol was used.¶
OIDC ID Tokens are typically passed as JWTs [RFC7519] in HTTP headers or URL fragments, which impose practical size limits. Browser URL length limits are commonly around 2048 bytes, and many HTTP servers reject headers exceeding 8192 bytes. When multiple credentials with many disclosed claims are included in the "presented_credentials" object, the resulting token may exceed these limits.¶
Implementations SHOULD consider the following mitigations:¶
The OP MUST handle the following failure scenarios gracefully:¶
The user declines to present credentials. The OP MAY either omit the "presented_credentials" claim entirely or return an OIDC error response (e.g., "access_denied") depending on whether the credential presentation was essential to the authentication.¶
The wallet does not respond within a reasonable time. The OP SHOULD treat this as equivalent to a rejection.¶
The wallet presents credentials that fail verification (expired, revoked, untrusted issuer). The OP MUST NOT include unverified credential claims in the "presented_credentials" object. The OP MAY proceed without those credentials or fail the authentication.¶
The wallet presents only a subset of the requested credentials. The OP MUST include only the successfully verified credentials and MUST NOT fabricate entries for missing credentials.¶
An OP MAY define custom OIDC scopes that map to specific credential presentation requests. For example, the scope "ehic" might trigger a request for an EHIC credential with a predefined set of claims.¶
When using scope-based mapping, the OP SHOULD document the mapping between scopes and credential types in its discovery metadata or out- of-band documentation. The OP MUST ensure that the scope semantics are stable and do not change unexpectedly for registered RPs.¶
Each OIDC Authentication Request that includes credential scopes MUST result in a new credential presentation from the wallet. The OP MUST initiate a fresh presentation protocol transaction (e.g., OpenID4VP, DIDComm) for every authentication request and MUST NOT reuse credentials from a previous presentation.¶
The OP MUST NOT store, cache, or persist credential data beyond the scope of the current authentication transaction. Once the OP has constructed the ID Token or UserInfo response and delivered it to the RP, it MUST discard the credential claims. This ensures that credential freshness is guaranteed and that the OP does not become an unnecessary repository of sensitive personal data.¶
This specification defines the data format of the "presented_credentials" claim, the mechanism for requesting and returning credential claims via OIDC, and the responsibilities of the OP and RP in that exchange. The following aspects are explicitly out of scope:¶
Credential validation policy. This specification does not define which issuers to trust, which revocation mechanisms to check, or what trust frameworks to apply. These decisions are deployment- specific and determined by the OP operator.¶
Business logic and authorization decisions. How the RP interprets the received claims -- for example, whether an EHIC credential grants access to a healthcare service, or whether a PDA1 is sufficient for a given transaction -- is entirely the RP's responsibility and outside this specification.¶
Credential issuance. This specification deals only with presentation of existing credentials, not with the issuance of new credentials (which is covered by OpenID4VCI).¶
Wallet implementation. The interaction between the OP and the wallet uses a presentation protocol such as OpenID4VP or DIDComm. This specification does not mandate a specific protocol and does not impose additional requirements on wallet implementations.¶
User consent and identity matching. How the OP associates a credential presentation with an OIDC subject identifier, and how user consent is obtained, are implementation details left to the OP.¶
In summary, this specification provides the plumbing for transporting verified credential claims through OIDC. Everything above that layer -- trust decisions, access control, and business rules -- is the domain of the deploying parties.¶
The OP MUST ensure that credential presentations are bound to the current authentication session. The OP SHOULD use nonces in the OpenID4VP request to prevent replay of previously captured VP Tokens.¶
The RP MUST validate standard JWT claims ("iat", "exp", "nonce") in the ID Token to ensure freshness of the "presented_credentials" claim.¶
ID Tokens containing "presented_credentials" may carry sensitive personal data (e.g., national ID numbers, health information). Implementations MUST use TLS for all token transmissions. The OP SHOULD prefer delivering credential claims via the UserInfo endpoint (which uses a back-channel request) rather than embedding them in the ID Token (which may be exposed in browser history or logs).¶
The OP MUST NOT allow external parties to inject or modify claims within the "presented_credentials" object. The OP MUST populate this claim exclusively from verified credential presentations. The ID Token MUST be signed by the OP to protect integrity.¶
When the OP dereferences external references contained in a "trusted_authorities" entry supplied via the RP's "dcql_query" (such as an "etsi_tl" trust list URI or an "openid_federation" entity identifier), it MUST enforce the following safeguards:¶
The OP MUST only fetch external trust material over HTTPS.¶
The OP MUST NOT dereference arbitrary URIs provided by an RP. The OP MUST restrict which URIs it is willing to fetch to prevent Server-Side Request Forgery (SSRF). The mechanism for this restriction (e.g., an allowlist, domain policy) is a deployment decision and outside the scope of this specification.¶
The OP MUST impose size limits on fetched documents to prevent resource exhaustion.¶
The OP SHOULD cache dereferenced trust material and enforce a minimum refresh interval to limit the impact of a compromised or unavailable remote trust material source.¶
If an external trust reference cannot be fetched or parsed, the OP MUST treat that "trusted_authorities" entry as contributing no authorities. Other entries in the same "trusted_authorities" array that were successfully resolved still apply. The OP MUST NOT treat an unresolved entry as matching all authorities.¶
The bridge architecture introduces the OP as a party that observes all credential claims presented by the user. This creates a correlation point. Deployments SHOULD consider the following:¶
The OP SHOULD request only the minimum claims necessary to satisfy the RP's request (selective disclosure).¶
The OP SHOULD NOT log or persist credential claims beyond what is necessary for the authentication session.¶
RPs SHOULD be aware that repeated presentations of the same credential claims across sessions may enable correlation by the OP.¶
Where possible, deployments SHOULD use pairwise subject identifiers to limit cross-RP correlation.¶
The claim name "presented_credentials" was chosen to be protocol- agnostic, clearly describing the content (credentials that were presented) without implying a dependency on any particular presentation protocol or namespace.¶
This specification requests registration of the following claim in the IANA "JSON Web Token Claims" registry:¶
"presented_credentials"¶
Digital credential claims obtained via a credential presentation flow, structured for consumption by OIDC Relying Parties.¶
IETF¶
Section 5.1.1 of this document¶
This specification requests registration of the following metadata parameters:¶
"credential_presentations_supported"¶
A JSON object describing the credential types the OP can collect via credential presentation and expose as OIDC claims.¶
IETF¶
Section 5.2 of this document¶
"dcql_query_supported"¶
A JSON boolean indicating whether the OP accepts a "dcql_query" member inside the OIDC "claims" request parameter as defined in the DCQL-based request mode.¶
IETF¶
Section 5.2 of this document¶
This specification establishes the "Credential Trust Status Values" registry. The registration policy is "Specification Required" as defined in Section 4.6 of [RFC8126].¶
Each entry in the registry contains the following fields:¶
A short string used as the value of the "trust_status" member of the Credential Entry "verification" object.¶
A brief description of the trust-status semantics.¶
The entity responsible for the registration.¶
Reference to the specification defining the value.¶
The initial contents of the registry are:¶
| Value | Description | Change Controller | Specification |
|---|---|---|---|
| not_checked | The OP performed no trust-status check for this credential | IETF | Section 5.1.2 of this document |
| unknown | The OP performed a trust-status check but the authoritative source returned no conclusive answer (e.g., ETSI Token Status List "unknown" state) | IETF | Section 5.1.2 of this document |
| valid | The credential's trust status was checked and is currently valid | IETF | Section 5.1.2 of this document |
| suspended | The credential is temporarily suspended by its issuer or trust framework | IETF | Section 5.1.2 of this document |
| revoked | The credential has been revoked by its issuer or trust framework | IETF | Section 5.1.2 of this document |
| expired | The credential has expired according to its own validity period | IETF | Section 5.1.2 of this document |
| invalid | The credential failed one or more verification checks | IETF | Section 5.1.2 of this document |
This specification establishes the "Credential Holder Binding Methods" registry. The registration policy is "Specification Required" as defined in Section 4.6 of [RFC8126].¶
Each entry in the registry contains the following fields:¶
A short string identifying the holder binding method.¶
A brief description of the method.¶
The entity responsible for the registration.¶
Reference to the specification defining the method.¶
The initial contents of the registry are:¶
| Method Name | Description | Change Controller | Specification |
|---|---|---|---|
| key_binding | Cryptographic proof of possession of a private key bound to the credential | IETF | Section 5.1.2 of this document |
| biometric | Biometric verification of the presenter against data bound to the credential | IETF | Section 5.1.2 of this document |
| pin | Verification of a PIN or passcode known to the credential holder | IETF | Section 5.1.2 of this document |
This appendix defines the concrete binding between the OIDC-level request defined in Section 4.1 and DCQL as specified in Section 6 of [OpenID4VP]. Deployments that use OpenID4VP as the presentation protocol between the OP and the wallet MUST follow this binding; other bindings are out of scope of this appendix.¶
For each credential type scope in the authorization request, the OP constructs one DCQL Credential Query as follows:¶
The scope value is used verbatim as the DCQL Credential Query "id".¶
The "format" is taken from the corresponding entry in "credential_presentations_supported".¶
The "meta" member is populated from the entry's "type": for
the dc+sd-jwt format the OP sets meta.vct_values to a JSON
array containing the "type" string; for the mso_mdoc format
the OP sets meta.doctype_value to the "type" string.¶
The "claims" array is either omitted or set to the deployment's pre-registered claim set for the credential type.¶
For example, given the discovery metadata:¶
{
"credential_presentations_supported": {
"ehic": {
"format": "dc+sd-jwt",
"type": "urn:eu.europa.ec.eudi:ehic:1"
},
"pda1": {
"format": "dc+sd-jwt",
"type": "urn:eu.europa.ec.eudi:pda1:1"
}
}
}
¶
and an RP request with scope=openid ehic pda1, the OP constructs
the following DCQL query:¶
{
"credentials": [
{
"id": "ehic",
"format": "dc+sd-jwt",
"meta": {
"vct_values": ["urn:eu.europa.ec.eudi:ehic:1"]
}
},
{
"id": "pda1",
"format": "dc+sd-jwt",
"meta": {
"vct_values": ["urn:eu.europa.ec.eudi:pda1:1"]
}
}
]
}
¶
The wallet returns a VP Token keyed by these same "id" values, allowing the OP to map presented credentials back to the corresponding scope.¶
When the RP supplied a "dcql_query" member in the OIDC "claims" request parameter, the OP MUST use that query as the DCQL query sent to the wallet, subject to the following:¶
RP-supplied Credential Query "id" values are forwarded to the wallet unchanged.¶
Each Credential Query MUST satisfy the type and scope checks of Section 4.1.2; otherwise the OP MUST reject the request.¶
The OP MUST augment the query with Credential Queries derived from any requested scopes not already covered, using the scope-based rules above, and MUST NOT reuse an "id" supplied by the RP.¶
The OP MUST NOT relax any constraint expressed by the RP (e.g., MUST NOT drop "trusted_authorities" or widen "values").¶
For each satisfied Credential Query, the OP populates a Credential Entry as defined in Section 5.1.2. The DCQL Credential Query "id" becomes the key in the enclosing Credential Set in the "presented_credentials" response.¶
When the RP's "dcql_query" contains "credential_sets", the OP returns one Credential Set object in the "presented_credentials" array for each satisfied entry in "credential_sets", populated with the Credential Entries from the matched AND-group. The OPTIONAL "id" of each Credential Set entry MAY be echoed in the response via the reserved "id" member described in Section 5.1.1.¶
DCQL value matching is defined as best-effort: the wallet SHOULD filter on the constraint but is not required to do so (see Section 6.4.1 of [OpenID4VP]). Consequently, the OP MUST NOT rely on the wallet to enforce "values" constraints and MUST always validate disclosed claim values against the RP's "values" requirements after receiving the presentation. Propagating the constraint to the wallet remains useful as a privacy optimisation, because it allows the wallet to avoid disclosing credentials that would not satisfy the request.¶
This appendix is reserved for a future DIDComm Present Proof binding. Its inclusion is intended to make the extension pattern explicit: bindings for additional presentation protocols may be added here without changing the protocol-agnostic contract in Section 5.4.¶
Several normative rules in this specification require comparing a disclosed claim value against entries in a "values" array. A disclosed value matches an entry if and only if both are of the same JSON type (as defined in [RFC8259]) and are equal under the following rules:¶
Strings are compared as sequences of Unicode code points. No Unicode normalization, case folding, or whitespace trimming is applied.¶
Numbers are compared by mathematical value, independent of their
lexical representation (for example, 1, 1.0, and 1e0 all
match).¶
Boolean values match only the identical boolean, and the null value matches only null.¶
Values of different JSON types never match (for example, the string "1" does not match the number 1). Objects and arrays are not expected in "values" entries; if present, they MUST be compared structurally, with member and element equality determined recursively by these same rules and object member order treated as insignificant.¶
The author would like to thank Patrick Amrein (Ubique) for reviews, comments, and contributions to this document.¶