A Dart library for building and validating Digital Credentials Query Language (DCQL) queries as defined in the OpenID for Verifiable Presentations (OpenID4VP) v1.0 specification.
Build complex credential queries with a fluent, type-safe API, validate them against the spec, and serialize them to JSON for transmission.
List of package versions and what specs they support
| version | Spec |
|---|---|
| v1.0.1 | v1.0 |
| v1.0.0 | v1.0 |
- Fluent Builder API: Construct complex nested queries with readable, chainable methods.
- Type Safety: Compile-time checks for known credential types (
mdoc,sd-jwt) and claims. - Spec Compliance: Built-in validation ensures your queries meet the DCQL specification requirements.
- Zero Boilerplate: No need to manually construct deeply nested Maps or JSON objects.
This library focuses exclusively on the Digital Credentials Query Language (DCQL) part of the OpenID4VP specification.
It does not handle
- Cryptographic operations (signing, encryption, or verification of credentials).
- PKI or Key Management.
- Transport protocols (OID4VP request/response handling).
It is designed to be used within a larger OpenID4VP implementation or by a Verifier application that needs to construct queries.
dart pub add openid4vp_dcqlimport 'dart:convert';
import 'package:openid4vp_dcql/openid4vp_dcql.dart';
void main() {
try {
final query = DcqlBuilder()
// Request an mDoc Driving License
.credential('credential-1', type: CredentialType.mdocDl)
.claim(Claims.mdocDl.firstName, id: 'first_name')
.claim(Claims.mdocDl.documentNumber, id: 'doc_number')
// Define combinations of claims that satisfy the requirement
.claimSet(["first_name", "doc_number"])
// Request an SD-JWT PID
.credential('credential-2', type: CredentialType.sdJwtPid)
.claim(Claims.sdJwtPid.documentNumber)
// Define logic between credentials (e.g., Credential 1 OR Credential 2)
.credentialSet()
.option(['credential-1'])
.option(['credential-2'])
// Build will throw a ValidationException if the query is invalid
// can be skipped by setting (skipValidation: true)
.build();
print(jsonEncode(query.toJson()));
} catch (e) {
print(e);
}
}You can also construct the query object directly without using the builder. However, you will lose some conveniences, such as automatic path prefixing (namespaces) for claims.
import 'dart:convert';
import 'package:openid4vp_dcql/openid4vp_dcql.dart';
void main() {
final query = DcqlQuery(
credentials: [
Credential(
id: 'credential-1',
format: Formats.mso_mdoc,
meta: Meta(meta: {'doctype_value': 'org.iso.18013.5.1.mDL'}),
claims: [
Claim(id: 'first_name', path: ['org.iso.18013.5.1', 'first_name']),
Claim(id: 'doc_number', path: ['org.iso.18013.5.1', 'document_number']),
],
claimSets: [
['first_name', 'doc_number']
],
),
Credential(
id: 'credential-2',
format: Formats.sd_jwt,
meta: Meta(meta: {'vcts_values': ['urn:eu.europa.ec.eudi.pid.1']}),
claims: [
Claim(path: ['document_number']),
],
),
],
credentialSets: [
CredentialSet(
options: [
['credential-1'],
['credential-2'],
],
),
],
);
// Validate the query structure
final validation = DcqlValidator().validate(query);
if (validation.isValid) {
print(jsonEncode(query.toJson()));
} else {
print('Invalid query: ${validation.errors}');
}
}The DcqlBuilder allows you to chain methods to define credentials, claims, and sets naturally.
The library includes a robust validator DcqlValidator that checks for:
- Uniqueness: Ensures all credential and claim IDs are unique within their scope.
- Referential Integrity: Verifies that all IDs referenced in
claim_setsandcredential_setsactually exist. - Structure: Checks for non-empty paths, correct value types, and required fields.
- Format Compliance: Validates format-specific requirements (e.g.,
doctype_valuefor mdoc).
You can validate a query object or a JSON string:
final validator = DcqlValidator();
// Validate a DcqlQuery object
final result = validator.validate(query);
// Validate a JSON string
final resultJson = validator.validateJson(jsonString);
if (result.isInvalid) {
print('Validation failed:');
for (final error in result.errors!) {
print('- $error');
}
}Note: The
DcqlBuilder.build()method automatically runs validation and throws aValidationExceptionif the query is invalid. To skip this check, use.build(skipValidation: true).
mso_mdoc(Mobile Driving License, etc.)dc+sd-jwt(SD-JWT VC)
Open an issue for discussion, then PR with tests.
MIT