Skip to main content

identity_kit/vc/
mod.rs

1//! Verifiable credentials and presentations secured as JWTs.
2//!
3//! The module implements two profiles over the same JOSE layer:
4//!
5//! - **VCDM 1.1 JWT profile** (§6.3.1 of the Verifiable Credentials Data Model 1.1):
6//!   [`Credential`] and [`Presentation`] map to and from a [`JwtClaims`] set whose `vc` or `vp`
7//!   claim holds the data model object and whose registered claims (`iss`, `sub`, `jti`, `nbf`,
8//!   `exp`, `aud`) carry the issuer, subject, id, validity period and audience.
9//! - **VCDM 2.0 with VC-JOSE-COSE**: [`CredentialV2`] and [`PresentationV2`] are themselves the
10//!   JWT payload (`typ: vc+jwt` or `vp+jwt`), and a secured credential travels inside a
11//!   presentation as an [`EnvelopedVc`] holding a `data:application/vc+jwt,…` URL.
12//!
13//! Both are plain data with open extension properties; `@context` is carried, never processed.
14//! [`ClaimPath`] points at a claim in any JSON credential: the claim path of SD-JWT VC §5.6.1 and
15//! the claims path pointer of OID4VP §7, which DCQL applies to every JSON-based format.
16//! [`JwtClaims`] lives in [`jose`](crate::jose) and is re-exported here; this module adds its
17//! conversions between `NumericDate` values and `chrono` times.
18//! [`Jwt`] is a compact JWS as a string, signed with any [`Signer`](crate::jose::Signer) through
19//! [`Jwt::sign`]. The [`validation`] module verifies and validates the JWTs: signature through
20//! a [`KeyResolver`](validation::KeyResolver) and a [`JwsVerifier`](crate::jose::JwsVerifier),
21//! binding of the signing key to the issuer or holder, validity period, audience, nonce and
22//! status.
23//!
24//! Timestamps are [`chrono::DateTime<Utc>`](chrono::DateTime) values, serialized as RFC 3339
25//! in UTC (`2010-01-01T19:23:24Z`), the `dateTimeStamp` form the data model requires.
26//!
27//! # Examples
28//!
29//! The JWT claims of VCDM 1.1 Example 31, decoded to a credential and back.
30//!
31//! ```
32//! use identity_kit::vc::{Credential, JwtClaims};
33//! use serde_json::json;
34//!
35//! let claims: JwtClaims = serde_json::from_value(json!({
36//!   "sub": "did:example:ebfeb1f712ebc6f1c276e12ec21",
37//!   "jti": "http://example.edu/credentials/3732",
38//!   "iss": "https://example.com/keys/foo.jwk",
39//!   "nbf": 1541493724,
40//!   "exp": 1573029723,
41//!   "nonce": "660!6345FSer",
42//!   "vc": {
43//!     "@context": [
44//!       "https://www.w3.org/2018/credentials/v1",
45//!       "https://www.w3.org/2018/credentials/examples/v1"
46//!     ],
47//!     "type": ["VerifiableCredential", "UniversityDegreeCredential"],
48//!     "credentialSubject": {
49//!       "degree": { "type": "BachelorDegree", "name": "Bachelor of Science and Arts" }
50//!     }
51//!   }
52//! }))?;
53//!
54//! let credential = Credential::from_jwt_claims(&claims)?;
55//! assert_eq!(credential.id.as_ref().map(|id| id.as_str()), Some("http://example.edu/credentials/3732"));
56//! assert_eq!(credential.issuer.id().as_str(), "https://example.com/keys/foo.jwk");
57//! assert_eq!(credential.issuance_date.to_rfc3339(), "2018-11-06T08:42:04+00:00");
58//! assert_eq!(
59//!     credential.subject().and_then(|s| s.id.as_ref()).map(|id| id.as_str()),
60//!     Some("did:example:ebfeb1f712ebc6f1c276e12ec21")
61//! );
62//!
63//! // The mapping is reversible; the custom `nonce` claim is the caller's to add back.
64//! let encoded = credential.to_jwt_claims()?.with_claim("nonce", "660!6345FSer");
65//! assert_eq!(encoded, claims);
66//! # Ok::<(), Box<dyn std::error::Error>>(())
67//! ```
68
69mod claims;
70mod credential;
71mod error;
72mod jwt;
73mod model;
74mod path;
75mod presentation;
76mod v2;
77pub mod validation;
78
79pub use credential::Credential;
80pub use error::CredentialError;
81pub use jwt::Jwt;
82#[cfg(feature = "status-list")]
83pub(crate) use jwt::required_numeric_date;
84
85pub use crate::jose::JwtClaims;
86#[cfg(feature = "status-list")]
87pub(crate) use crate::jose::numeric_date;
88pub use model::{CONTEXT_V1, CONTEXT_V2, Party, Subject, TypedObject};
89pub use path::{ClaimPath, ClaimPathError, PathComponent};
90pub use presentation::Presentation;
91pub use v2::{CredentialV2, EnvelopedVc, EnvelopedVp, PresentationV2};