diff --git a/bindings/wasm/docs/api-reference.md b/bindings/wasm/docs/api-reference.md
index 0cb70751b9..631b6a8194 100644
--- a/bindings/wasm/docs/api-reference.md
+++ b/bindings/wasm/docs/api-reference.md
@@ -26,6 +26,11 @@
Note that having an instance of this type only means the JWS it was constructed from was verified.
It does not imply anything about a potentially present proof property on the credential itself.
+DecodedJwtPresentation
+A cryptographically verified and decoded presentation.
+Note that having an instance of this type only means the JWS it was constructed from was verified.
+It does not imply anything about a potentially present proof property on the presentation itself.
+
DomainLinkageConfiguration
DID Configuration Resource which contains Domain Linkage Credentials.
It can be placed in an origin's .well-known
directory to prove linkage between the origin and a DID.
@@ -79,6 +84,15 @@ and resolution of DID documents in Alias Outputs.
JwtCredentialValidator
A type for decoding and validating Credentials
.
+JwtPresentation
+
+JwtPresentationOptions
+
+JwtPresentationValidationOptions
+Options to declare validation criteria when validating presentation.
+
+JwtPresentationValidator
+
KeyPair
LinkedDomainService
@@ -151,12 +165,8 @@ See IVerifierOptions
.
## Members
-KeyType
-
StateMetadataEncoding
-MethodRelationship
-
StatusCheck
Controls validation behaviour when checking whether or not a credential has been revoked by its
credentialStatus
.
@@ -199,20 +209,15 @@ This variant is the default used if no other variant is specified when construct
FirstError
Return after the first error occurs.
+KeyType
+
+MethodRelationship
+
## Functions
-start()
-Initializes the console error panic hook for better error messages
-
-encodeB64(data) ⇒ string
-Encode the given bytes in url-safe base64.
-
-decodeB64(data) ⇒ Uint8Array
-Decode the given url-safe base64-encoded slice into its raw bytes.
-
verifyEdDSA(alg, signingInput, decodedSignature, publicKey)
Verify a JWS signature secured with the JwsAlgorithm::EdDSA
algorithm.
Only the EdCurve::Ed25519
variant is supported for now.
@@ -222,6 +227,15 @@ the IOTA Identity Framework.
This function does not check whether alg = EdDSA
in the protected header. Callers are expected to assert this
prior to calling the function.
+encodeB64(data) ⇒ string
+Encode the given bytes in url-safe base64.
+
+decodeB64(data) ⇒ Uint8Array
+Decode the given url-safe base64-encoded slice into its raw bytes.
+
+start()
+Initializes the console error panic hook for better error messages
+
@@ -455,6 +469,7 @@ A method-agnostic DID Document.
* [.purgeMethod(storage, id)](#CoreDocument+purgeMethod) ⇒ Promise.<void>
* [.createJws(storage, fragment, payload, options)](#CoreDocument+createJws) ⇒ [Promise.<Jws>
](#Jws)
* [.createCredentialJwt(storage, fragment, credential, options)](#CoreDocument+createCredentialJwt) ⇒ [Promise.<Jwt>
](#Jwt)
+ * [.createPresentationJwt(storage, fragment, presentation, signature_options, presentation_options)](#CoreDocument+createPresentationJwt) ⇒ [Promise.<Jwt>
](#Jwt)
* _static_
* [.fromJSON(json)](#CoreDocument.fromJSON) ⇒ [CoreDocument
](#CoreDocument)
@@ -888,6 +903,19 @@ produced by the corresponding private key backed by the `storage` in accordance
| credential | [Credential
](#Credential) |
| options | [JwsSignatureOptions
](#JwsSignatureOptions) |
+
+
+### coreDocument.createPresentationJwt(storage, fragment, presentation, signature_options, presentation_options) ⇒ [Promise.<Jwt>
](#Jwt)
+**Kind**: instance method of [CoreDocument
](#CoreDocument)
+
+| Param | Type |
+| --- | --- |
+| storage | [Storage
](#Storage) |
+| fragment | string
|
+| presentation | [JwtPresentation
](#JwtPresentation) |
+| signature_options | [JwsSignatureOptions
](#JwsSignatureOptions) |
+| presentation_options | [JwtPresentationOptions
](#JwtPresentationOptions) |
+
### CoreDocument.fromJSON(json) ⇒ [CoreDocument
](#CoreDocument)
@@ -1520,6 +1548,61 @@ Consumes the object and returns the decoded credential.
This destroys the `DecodedCredential` object.
**Kind**: instance method of [DecodedJwtCredential
](#DecodedJwtCredential)
+
+
+## DecodedJwtPresentation
+A cryptographically verified and decoded presentation.
+
+Note that having an instance of this type only means the JWS it was constructed from was verified.
+It does not imply anything about a potentially present proof property on the presentation itself.
+
+**Kind**: global class
+
+* [DecodedJwtPresentation](#DecodedJwtPresentation)
+ * [.presentation()](#DecodedJwtPresentation+presentation) ⇒ [JwtPresentation
](#JwtPresentation)
+ * [.protectedHeader()](#DecodedJwtPresentation+protectedHeader) ⇒ [JwsHeader
](#JwsHeader)
+ * [.intoCredential()](#DecodedJwtPresentation+intoCredential) ⇒ [JwtPresentation
](#JwtPresentation)
+ * [.expirationDate()](#DecodedJwtPresentation+expirationDate) ⇒ [Timestamp
](#Timestamp) \| undefined
+ * [.issuanceDate()](#DecodedJwtPresentation+issuanceDate) ⇒ [Timestamp
](#Timestamp) \| undefined
+ * [.credentials()](#DecodedJwtPresentation+credentials) ⇒ [Array.<DecodedJwtCredential>
](#DecodedJwtCredential)
+
+
+
+### decodedJwtPresentation.presentation() ⇒ [JwtPresentation
](#JwtPresentation)
+**Kind**: instance method of [DecodedJwtPresentation
](#DecodedJwtPresentation)
+
+
+### decodedJwtPresentation.protectedHeader() ⇒ [JwsHeader
](#JwsHeader)
+Returns a copy of the protected header parsed from the decoded JWS.
+
+**Kind**: instance method of [DecodedJwtPresentation
](#DecodedJwtPresentation)
+
+
+### decodedJwtPresentation.intoCredential() ⇒ [JwtPresentation
](#JwtPresentation)
+Consumes the object and returns the decoded presentation.
+
+### Warning
+This destroys the `DecodedJwtPresentation` object.
+
+**Kind**: instance method of [DecodedJwtPresentation
](#DecodedJwtPresentation)
+
+
+### decodedJwtPresentation.expirationDate() ⇒ [Timestamp
](#Timestamp) \| undefined
+The expiration date parsed from the JWT claims.
+
+**Kind**: instance method of [DecodedJwtPresentation
](#DecodedJwtPresentation)
+
+
+### decodedJwtPresentation.issuanceDate() ⇒ [Timestamp
](#Timestamp) \| undefined
+The issuance dated parsed from the JWT claims.
+
+**Kind**: instance method of [DecodedJwtPresentation
](#DecodedJwtPresentation)
+
+
+### decodedJwtPresentation.credentials() ⇒ [Array.<DecodedJwtCredential>
](#DecodedJwtCredential)
+The credentials included in the presentation (decoded).
+
+**Kind**: instance method of [DecodedJwtPresentation
](#DecodedJwtPresentation)
## DomainLinkageConfiguration
@@ -2058,6 +2141,7 @@ Deserializes an instance from a JSON object.
* [.purgeMethod(storage, id)](#IotaDocument+purgeMethod) ⇒ Promise.<void>
* [.createJwt(storage, fragment, payload, options)](#IotaDocument+createJwt) ⇒ [Promise.<Jws>
](#Jws)
* [.createCredentialJwt(storage, fragment, credential, options)](#IotaDocument+createCredentialJwt) ⇒ [Promise.<Jwt>
](#Jwt)
+ * [.createPresentationJwt(storage, fragment, presentation, signature_options, presentation_options)](#IotaDocument+createPresentationJwt) ⇒ [Promise.<Jwt>
](#Jwt)
* _static_
* [.newWithId(id)](#IotaDocument.newWithId) ⇒ [IotaDocument
](#IotaDocument)
* [.unpackFromOutput(did, aliasOutput, allowEmpty, tokenSupply)](#IotaDocument.unpackFromOutput) ⇒ [IotaDocument
](#IotaDocument)
@@ -2564,6 +2648,25 @@ produced by the corresponding private key backed by the `storage` in accordance
| credential | [Credential
](#Credential) |
| options | [JwsSignatureOptions
](#JwsSignatureOptions) |
+
+
+### iotaDocument.createPresentationJwt(storage, fragment, presentation, signature_options, presentation_options) ⇒ [Promise.<Jwt>
](#Jwt)
+Produces a JWT where the payload is produced from the given `presentation`
+in accordance with [VC-JWT version 1.1](https://w3c.github.io/vc-jwt/#version-1.1).
+
+The `kid` in the protected header is the `id` of the method identified by `fragment` and the JWS signature will be
+produced by the corresponding private key backed by the `storage` in accordance with the passed `options`.
+
+**Kind**: instance method of [IotaDocument
](#IotaDocument)
+
+| Param | Type |
+| --- | --- |
+| storage | [Storage
](#Storage) |
+| fragment | string
|
+| presentation | [JwtPresentation
](#JwtPresentation) |
+| signature_options | [JwsSignatureOptions
](#JwsSignatureOptions) |
+| presentation_options | [JwtPresentationOptions
](#JwtPresentationOptions) |
+
### IotaDocument.newWithId(id) ⇒ [IotaDocument
](#IotaDocument)
@@ -3815,6 +3918,297 @@ Fails if the issuer field is not a valid DID.
| --- | --- |
| credential | [Credential
](#Credential) |
+
+
+## JwtPresentation
+**Kind**: global class
+
+* [JwtPresentation](#JwtPresentation)
+ * [new JwtPresentation(values)](#new_JwtPresentation_new)
+ * _instance_
+ * [.context()](#JwtPresentation+context) ⇒ Array.<(string\|Record.<string, any>)>
+ * [.id()](#JwtPresentation+id) ⇒ string
\| undefined
+ * [.type()](#JwtPresentation+type) ⇒ Array.<string>
+ * [.verifiableCredential()](#JwtPresentation+verifiableCredential) ⇒ [Array.<Jwt>
](#Jwt)
+ * [.holder()](#JwtPresentation+holder) ⇒ string
+ * [.refreshService()](#JwtPresentation+refreshService) ⇒ Array.<RefreshService>
+ * [.termsOfUse()](#JwtPresentation+termsOfUse) ⇒ Array.<Policy>
+ * [.proof()](#JwtPresentation+proof) ⇒ Map.<string, any>
\| undefined
+ * [.properties()](#JwtPresentation+properties) ⇒ Map.<string, any>
+ * [.toJSON()](#JwtPresentation+toJSON) ⇒ any
+ * [.clone()](#JwtPresentation+clone) ⇒ [JwtPresentation
](#JwtPresentation)
+ * _static_
+ * [.BaseContext()](#JwtPresentation.BaseContext) ⇒ string
+ * [.BaseType()](#JwtPresentation.BaseType) ⇒ string
+ * [.fromJSON(json)](#JwtPresentation.fromJSON) ⇒ [JwtPresentation
](#JwtPresentation)
+
+
+
+### new JwtPresentation(values)
+Constructs a new presentation.
+
+
+| Param | Type |
+| --- | --- |
+| values | IJwtPresentation
|
+
+
+
+### jwtPresentation.context() ⇒ Array.<(string\|Record.<string, any>)>
+Returns a copy of the JSON-LD context(s) applicable to the presentation.
+
+**Kind**: instance method of [JwtPresentation
](#JwtPresentation)
+
+
+### jwtPresentation.id() ⇒ string
\| undefined
+Returns a copy of the unique `URI` identifying the presentation.
+
+**Kind**: instance method of [JwtPresentation
](#JwtPresentation)
+
+
+### jwtPresentation.type() ⇒ Array.<string>
+Returns a copy of the URIs defining the type of the presentation.
+
+**Kind**: instance method of [JwtPresentation
](#JwtPresentation)
+
+
+### jwtPresentation.verifiableCredential() ⇒ [Array.<Jwt>
](#Jwt)
+Returns a copy of the [Credential](#Credential)(s) expressing the claims of the presentation.
+
+**Kind**: instance method of [JwtPresentation
](#JwtPresentation)
+
+
+### jwtPresentation.holder() ⇒ string
+Returns a copy of the URI of the entity that generated the presentation.
+
+**Kind**: instance method of [JwtPresentation
](#JwtPresentation)
+
+
+### jwtPresentation.refreshService() ⇒ Array.<RefreshService>
+Returns a copy of the service(s) used to refresh an expired [Credential](#Credential) in the presentation.
+
+**Kind**: instance method of [JwtPresentation
](#JwtPresentation)
+
+
+### jwtPresentation.termsOfUse() ⇒ Array.<Policy>
+Returns a copy of the terms-of-use specified by the presentation holder
+
+**Kind**: instance method of [JwtPresentation
](#JwtPresentation)
+
+
+### jwtPresentation.proof() ⇒ Map.<string, any>
\| undefined
+Returns a copy of the proof property.
+
+**Kind**: instance method of [JwtPresentation
](#JwtPresentation)
+
+
+### jwtPresentation.properties() ⇒ Map.<string, any>
+Returns a copy of the miscellaneous properties on the presentation.
+
+**Kind**: instance method of [JwtPresentation
](#JwtPresentation)
+
+
+### jwtPresentation.toJSON() ⇒ any
+Serializes this to a JSON object.
+
+**Kind**: instance method of [JwtPresentation
](#JwtPresentation)
+
+
+### jwtPresentation.clone() ⇒ [JwtPresentation
](#JwtPresentation)
+Deep clones the object.
+
+**Kind**: instance method of [JwtPresentation
](#JwtPresentation)
+
+
+### JwtPresentation.BaseContext() ⇒ string
+Returns the base JSON-LD context.
+
+**Kind**: static method of [JwtPresentation
](#JwtPresentation)
+
+
+### JwtPresentation.BaseType() ⇒ string
+Returns the base type.
+
+**Kind**: static method of [JwtPresentation
](#JwtPresentation)
+
+
+### JwtPresentation.fromJSON(json) ⇒ [JwtPresentation
](#JwtPresentation)
+Deserializes an instance from a JSON object.
+
+**Kind**: static method of [JwtPresentation
](#JwtPresentation)
+
+| Param | Type |
+| --- | --- |
+| json | any
|
+
+
+
+## JwtPresentationOptions
+**Kind**: global class
+
+* [JwtPresentationOptions](#JwtPresentationOptions)
+ * [new JwtPresentationOptions(options)](#new_JwtPresentationOptions_new)
+ * _instance_
+ * [.toJSON()](#JwtPresentationOptions+toJSON) ⇒ any
+ * [.clone()](#JwtPresentationOptions+clone) ⇒ [JwtPresentationOptions
](#JwtPresentationOptions)
+ * _static_
+ * [.default()](#JwtPresentationOptions.default) ⇒ [JwtPresentationOptions
](#JwtPresentationOptions)
+ * [.fromJSON(json)](#JwtPresentationOptions.fromJSON) ⇒ [JwtPresentationOptions
](#JwtPresentationOptions)
+
+
+
+### new JwtPresentationOptions(options)
+Creates a new `JwtPresentationOptions` from the given fields.
+
+Throws an error if any of the options are invalid.
+
+
+| Param | Type |
+| --- | --- |
+| options | IJwtPresentationOptions
\| undefined
|
+
+
+
+### jwtPresentationOptions.toJSON() ⇒ any
+Serializes this to a JSON object.
+
+**Kind**: instance method of [JwtPresentationOptions
](#JwtPresentationOptions)
+
+
+### jwtPresentationOptions.clone() ⇒ [JwtPresentationOptions
](#JwtPresentationOptions)
+Deep clones the object.
+
+**Kind**: instance method of [JwtPresentationOptions
](#JwtPresentationOptions)
+
+
+### JwtPresentationOptions.default() ⇒ [JwtPresentationOptions
](#JwtPresentationOptions)
+Creates a new `JwtPresentationOptions` with defaults.
+
+**Kind**: static method of [JwtPresentationOptions
](#JwtPresentationOptions)
+
+
+### JwtPresentationOptions.fromJSON(json) ⇒ [JwtPresentationOptions
](#JwtPresentationOptions)
+Deserializes an instance from a JSON object.
+
+**Kind**: static method of [JwtPresentationOptions
](#JwtPresentationOptions)
+
+| Param | Type |
+| --- | --- |
+| json | any
|
+
+
+
+## JwtPresentationValidationOptions
+Options to declare validation criteria when validating presentation.
+
+**Kind**: global class
+
+* [JwtPresentationValidationOptions](#JwtPresentationValidationOptions)
+ * [new JwtPresentationValidationOptions(options)](#new_JwtPresentationValidationOptions_new)
+ * _instance_
+ * [.toJSON()](#JwtPresentationValidationOptions+toJSON) ⇒ any
+ * [.clone()](#JwtPresentationValidationOptions+clone) ⇒ [JwtPresentationValidationOptions
](#JwtPresentationValidationOptions)
+ * _static_
+ * [.default()](#JwtPresentationValidationOptions.default) ⇒ [JwtPresentationValidationOptions
](#JwtPresentationValidationOptions)
+ * [.fromJSON(json)](#JwtPresentationValidationOptions.fromJSON) ⇒ [JwtPresentationValidationOptions
](#JwtPresentationValidationOptions)
+
+
+
+### new JwtPresentationValidationOptions(options)
+Creates a new `JwtPresentationValidationOptions` from the given fields.
+
+Throws an error if any of the options are invalid.
+
+
+| Param | Type |
+| --- | --- |
+| options | IJwtPresentationValidationOptions
|
+
+
+
+### jwtPresentationValidationOptions.toJSON() ⇒ any
+Serializes this to a JSON object.
+
+**Kind**: instance method of [JwtPresentationValidationOptions
](#JwtPresentationValidationOptions)
+
+
+### jwtPresentationValidationOptions.clone() ⇒ [JwtPresentationValidationOptions
](#JwtPresentationValidationOptions)
+Deep clones the object.
+
+**Kind**: instance method of [JwtPresentationValidationOptions
](#JwtPresentationValidationOptions)
+
+
+### JwtPresentationValidationOptions.default() ⇒ [JwtPresentationValidationOptions
](#JwtPresentationValidationOptions)
+Creates a new `JwtPresentationValidationOptions` with defaults.
+
+**Kind**: static method of [JwtPresentationValidationOptions
](#JwtPresentationValidationOptions)
+
+
+### JwtPresentationValidationOptions.fromJSON(json) ⇒ [JwtPresentationValidationOptions
](#JwtPresentationValidationOptions)
+Deserializes an instance from a JSON object.
+
+**Kind**: static method of [JwtPresentationValidationOptions
](#JwtPresentationValidationOptions)
+
+| Param | Type |
+| --- | --- |
+| json | any
|
+
+
+
+## JwtPresentationValidator
+**Kind**: global class
+
+* [JwtPresentationValidator](#JwtPresentationValidator)
+ * [new JwtPresentationValidator(signature_verifier)](#new_JwtPresentationValidator_new)
+ * _instance_
+ * [.validate(presentation_jwt, holder, issuers, options, fail_fast)](#JwtPresentationValidator+validate) ⇒ [DecodedJwtPresentation
](#DecodedJwtPresentation)
+ * _static_
+ * [.checkStructure(presentation)](#JwtPresentationValidator.checkStructure)
+ * [.extractDids(presentation)](#JwtPresentationValidator.extractDids) ⇒ JwtPresentationDids
+
+
+
+### new JwtPresentationValidator(signature_verifier)
+Creates a new `JwtPresentationValidator`. If a `signature_verifier` is provided it will be used when
+verifying decoded JWS signatures, otherwise the default which is only capable of handling the `EdDSA`
+algorithm will be used.
+
+
+| Param | Type |
+| --- | --- |
+| signature_verifier | IJwsVerifier
\| undefined
|
+
+
+
+### jwtPresentationValidator.validate(presentation_jwt, holder, issuers, options, fail_fast) ⇒ [DecodedJwtPresentation
](#DecodedJwtPresentation)
+**Kind**: instance method of [JwtPresentationValidator
](#JwtPresentationValidator)
+
+| Param | Type |
+| --- | --- |
+| presentation_jwt | [Jwt
](#Jwt) |
+| holder | [CoreDocument
](#CoreDocument) \| IToCoreDocument
|
+| issuers | Array.<(CoreDocument\|IToCoreDocument)>
|
+| options | [JwtPresentationValidationOptions
](#JwtPresentationValidationOptions) |
+| fail_fast | number
|
+
+
+
+### JwtPresentationValidator.checkStructure(presentation)
+**Kind**: static method of [JwtPresentationValidator
](#JwtPresentationValidator)
+
+| Param | Type |
+| --- | --- |
+| presentation | [JwtPresentation
](#JwtPresentation) |
+
+
+
+### JwtPresentationValidator.extractDids(presentation) ⇒ JwtPresentationDids
+**Kind**: static method of [JwtPresentationValidator
](#JwtPresentationValidator)
+
+| Param | Type |
+| --- | --- |
+| presentation | [Jwt
](#Jwt) |
+
## KeyPair
@@ -5431,18 +5825,10 @@ This is possible because Ed25519 is birationally equivalent to Curve25519 used b
| --- | --- |
| publicKey | Uint8Array
|
-
-
-## KeyType
-**Kind**: global variable
## StateMetadataEncoding
**Kind**: global variable
-
-
-## MethodRelationship
-**Kind**: global variable
## StatusCheck
@@ -5521,12 +5907,36 @@ Return all errors that occur during validation.
Return after the first error occurs.
**Kind**: global variable
-
+
-## start()
-Initializes the console error panic hook for better error messages
+## KeyType
+**Kind**: global variable
+
+
+## MethodRelationship
+**Kind**: global variable
+
+
+## verifyEdDSA(alg, signingInput, decodedSignature, publicKey)
+Verify a JWS signature secured with the `JwsAlgorithm::EdDSA` algorithm.
+Only the `EdCurve::Ed25519` variant is supported for now.
+
+This function is useful when one is building an `IJwsVerifier` that extends the default provided by
+the IOTA Identity Framework.
+
+# Warning
+This function does not check whether `alg = EdDSA` in the protected header. Callers are expected to assert this
+prior to calling the function.
**Kind**: global function
+
+| Param | Type |
+| --- | --- |
+| alg | JwsAlgorithm
|
+| signingInput | Uint8Array
|
+| decodedSignature | Uint8Array
|
+| publicKey | [Jwk
](#Jwk) |
+
## encodeB64(data) ⇒ string
@@ -5549,25 +5959,9 @@ Decode the given url-safe base64-encoded slice into its raw bytes.
| --- | --- |
| data | Uint8Array
|
-
-
-## verifyEdDSA(alg, signingInput, decodedSignature, publicKey)
-Verify a JWS signature secured with the `JwsAlgorithm::EdDSA` algorithm.
-Only the `EdCurve::Ed25519` variant is supported for now.
-
-This function is useful when one is building an `IJwsVerifier` that extends the default provided by
-the IOTA Identity Framework.
+
-# Warning
-This function does not check whether `alg = EdDSA` in the protected header. Callers are expected to assert this
-prior to calling the function.
+## start()
+Initializes the console error panic hook for better error messages
**Kind**: global function
-
-| Param | Type |
-| --- | --- |
-| alg | JwsAlgorithm
|
-| signingInput | Uint8Array
|
-| decodedSignature | Uint8Array
|
-| publicKey | [Jwk
](#Jwk) |
-
diff --git a/bindings/wasm/src/credential/jwt_credential_validation/decoded_jwt_credential.rs b/bindings/wasm/src/credential/jwt_credential_validation/decoded_jwt_credential.rs
index 14dfb1ce5a..4630c82e45 100644
--- a/bindings/wasm/src/credential/jwt_credential_validation/decoded_jwt_credential.rs
+++ b/bindings/wasm/src/credential/jwt_credential_validation/decoded_jwt_credential.rs
@@ -37,3 +37,9 @@ impl WasmDecodedJwtCredential {
WasmCredential(self.0.credential)
}
}
+
+impl From for WasmDecodedJwtCredential {
+ fn from(credential: DecodedJwtCredential) -> Self {
+ Self(credential)
+ }
+}
diff --git a/bindings/wasm/src/credential/jwt_credential_validation/options.rs b/bindings/wasm/src/credential/jwt_credential_validation/options.rs
index 84a40393fe..9c1af47991 100644
--- a/bindings/wasm/src/credential/jwt_credential_validation/options.rs
+++ b/bindings/wasm/src/credential/jwt_credential_validation/options.rs
@@ -69,6 +69,5 @@ interface IJwtCredentialValidationOptions {
readonly status?: StatusCheck;
/** Options which affect the verification of the signature on the credential. */
- readonly verifierOptions?: VerifierOptions;
-
+ readonly verifierOptions?: JwsVerificationOptions;
}"#;
diff --git a/bindings/wasm/src/credential/jwt_presentation/jwt_presentation.rs b/bindings/wasm/src/credential/jwt_presentation/jwt_presentation.rs
new file mode 100644
index 0000000000..05209b90dd
--- /dev/null
+++ b/bindings/wasm/src/credential/jwt_presentation/jwt_presentation.rs
@@ -0,0 +1,147 @@
+// Copyright 2020-2023 IOTA Stiftung
+// SPDX-License-Identifier: Apache-2.0
+
+use identity_iota::core::Context;
+use identity_iota::core::Object;
+use identity_iota::credential::JwtPresentation;
+use identity_iota::credential::JwtPresentationBuilder;
+use wasm_bindgen::prelude::*;
+use wasm_bindgen::JsCast;
+
+use crate::common::ArrayString;
+use crate::common::MapStringAny;
+use crate::credential::jwt_presentation::jwt_presentation_builder::IJwtPresentation;
+use crate::credential::ArrayContext;
+use crate::credential::ArrayJwt;
+use crate::credential::ArrayPolicy;
+use crate::credential::ArrayRefreshService;
+use crate::credential::WasmJwt;
+use crate::error::Result;
+use crate::error::WasmResult;
+
+#[wasm_bindgen(js_name = JwtPresentation, inspectable)]
+pub struct WasmJwtPresentation(pub(crate) JwtPresentation);
+
+#[wasm_bindgen(js_class = JwtPresentation)]
+impl WasmJwtPresentation {
+ /// Returns the base JSON-LD context.
+ #[wasm_bindgen(js_name = "BaseContext")]
+ pub fn base_context() -> Result {
+ match JwtPresentation::::base_context() {
+ Context::Url(url) => Ok(url.to_string()),
+ Context::Obj(_) => Err(JsError::new("JwtPresentation.BaseContext should be a single URL").into()),
+ }
+ }
+
+ /// Returns the base type.
+ #[wasm_bindgen(js_name = "BaseType")]
+ pub fn base_type() -> String {
+ JwtPresentation::::base_type().to_owned()
+ }
+
+ /// Constructs a new presentation.
+ #[wasm_bindgen(constructor)]
+ pub fn new(values: IJwtPresentation) -> Result {
+ let builder: JwtPresentationBuilder = JwtPresentationBuilder::try_from(values)?;
+ builder.build().map(Self).wasm_result()
+ }
+
+ /// Returns a copy of the JSON-LD context(s) applicable to the presentation.
+ #[wasm_bindgen]
+ pub fn context(&self) -> Result {
+ self
+ .0
+ .context
+ .iter()
+ .map(JsValue::from_serde)
+ .collect::>()
+ .wasm_result()
+ .map(|value| value.unchecked_into::())
+ }
+
+ /// Returns a copy of the unique `URI` identifying the presentation.
+ #[wasm_bindgen]
+ pub fn id(&self) -> Option {
+ self.0.id.as_ref().map(|url| url.to_string())
+ }
+
+ /// Returns a copy of the URIs defining the type of the presentation.
+ #[wasm_bindgen(js_name = "type")]
+ pub fn types(&self) -> ArrayString {
+ self
+ .0
+ .types
+ .iter()
+ .map(|s| s.as_str())
+ .map(JsValue::from_str)
+ .collect::()
+ .unchecked_into::()
+ }
+
+ /// Returns the JWT credentials expressing the claims of the presentation.
+ #[wasm_bindgen(js_name = verifiableCredential)]
+ pub fn verifiable_credential(&self) -> ArrayJwt {
+ self
+ .0
+ .verifiable_credential
+ .iter()
+ .cloned()
+ .map(WasmJwt::new)
+ .map(JsValue::from)
+ .collect::()
+ .unchecked_into::()
+ }
+
+ /// Returns a copy of the URI of the entity that generated the presentation.
+ #[wasm_bindgen]
+ pub fn holder(&self) -> String {
+ self.0.holder.as_ref().to_string()
+ }
+
+ /// Returns a copy of the service(s) used to refresh an expired {@link Credential} in the presentation.
+ #[wasm_bindgen(js_name = "refreshService")]
+ pub fn refresh_service(&self) -> Result {
+ self
+ .0
+ .refresh_service
+ .iter()
+ .map(JsValue::from_serde)
+ .collect::>()
+ .wasm_result()
+ .map(|value| value.unchecked_into::())
+ }
+
+ /// Returns a copy of the terms-of-use specified by the presentation holder
+ #[wasm_bindgen(js_name = "termsOfUse")]
+ pub fn terms_of_use(&self) -> Result {
+ self
+ .0
+ .terms_of_use
+ .iter()
+ .map(JsValue::from_serde)
+ .collect::>()
+ .wasm_result()
+ .map(|value| value.unchecked_into::())
+ }
+
+ /// Optional proof that can be verified by users in addition to JWS.
+ #[wasm_bindgen]
+ pub fn proof(&self) -> Result> {
+ self.0.proof.clone().map(MapStringAny::try_from).transpose()
+ }
+
+ /// Returns a copy of the miscellaneous properties on the presentation.
+ #[wasm_bindgen]
+ pub fn properties(&self) -> Result {
+ MapStringAny::try_from(&self.0.properties)
+ }
+}
+
+impl_wasm_json!(WasmJwtPresentation, JwtPresentation);
+impl_wasm_clone!(WasmJwtPresentation, JwtPresentation);
+
+impl From for WasmJwtPresentation {
+ fn from(presentation: JwtPresentation) -> WasmJwtPresentation {
+ Self(presentation)
+ }
+}
diff --git a/bindings/wasm/src/credential/jwt_presentation/jwt_presentation_builder.rs b/bindings/wasm/src/credential/jwt_presentation/jwt_presentation_builder.rs
new file mode 100644
index 0000000000..5fee2025a3
--- /dev/null
+++ b/bindings/wasm/src/credential/jwt_presentation/jwt_presentation_builder.rs
@@ -0,0 +1,102 @@
+// Copyright 2020-2023 IOTA Stiftung
+// SPDX-License-Identifier: Apache-2.0
+
+use identity_iota::core::Context;
+use identity_iota::core::Object;
+use identity_iota::core::OneOrMany;
+use identity_iota::core::Url;
+use identity_iota::credential::Jwt;
+use identity_iota::credential::JwtPresentationBuilder;
+use identity_iota::credential::Policy;
+use identity_iota::credential::RefreshService;
+use proc_typescript::typescript;
+use wasm_bindgen::prelude::*;
+
+use crate::error::WasmResult;
+
+impl TryFrom for JwtPresentationBuilder {
+ type Error = JsValue;
+
+ fn try_from(values: IJwtPresentation) -> std::result::Result {
+ let IJwtPresentationHelper {
+ context,
+ id,
+ r#type,
+ verifiable_credential,
+ holder,
+ refresh_service,
+ terms_of_use,
+ properties,
+ } = values.into_serde::().wasm_result()?;
+
+ let mut builder: JwtPresentationBuilder =
+ JwtPresentationBuilder::new(Url::parse(holder).wasm_result()?, properties);
+
+ if let Some(context) = context {
+ for value in context.into_vec() {
+ builder = builder.context(value);
+ }
+ }
+ if let Some(id) = id {
+ builder = builder.id(Url::parse(id).wasm_result()?);
+ }
+ if let Some(types) = r#type {
+ for value in types.iter() {
+ builder = builder.type_(value);
+ }
+ }
+ for credential in verifiable_credential.into_vec() {
+ builder = builder.credential(Jwt::new(credential));
+ }
+ if let Some(refresh_service) = refresh_service {
+ for service in refresh_service.into_vec() {
+ builder = builder.refresh_service(service);
+ }
+ }
+ if let Some(terms_of_use) = terms_of_use {
+ for policy in terms_of_use.into_vec() {
+ builder = builder.terms_of_use(policy);
+ }
+ }
+
+ Ok(builder)
+ }
+}
+
+#[wasm_bindgen]
+extern "C" {
+ #[wasm_bindgen(typescript_type = "IJwtPresentation")]
+ pub type IJwtPresentation;
+}
+
+/// Fields for constructing a new {@link JwtPresentation}.
+#[derive(Deserialize)]
+#[serde(rename_all = "camelCase")]
+#[typescript(name = "IJwtPresentation", readonly, optional)]
+struct IJwtPresentationHelper {
+ /// The JSON-LD context(s) applicable to the presentation.
+ #[typescript(type = "string | Record | Array>")]
+ context: Option>,
+ /// A unique URI that may be used to identify the presentation.
+ #[typescript(type = "string")]
+ id: Option,
+ /// One or more URIs defining the type of the presentation. Contains the base context by default.
+ #[typescript(name = "type", type = "string | Array")]
+ r#type: Option>,
+ /// JWT Credential(s) expressing the claims of the presentation.
+ #[typescript(optional = false, name = "verifiableCredential", type = "string | Array")]
+ verifiable_credential: OneOrMany,
+ /// The entity that generated the presentation.
+ #[typescript(optional = false, type = "string | CoreDID | IotaDID ")]
+ holder: String,
+ /// Service(s) used to refresh an expired {@link Credential} in the presentation.
+ #[typescript(name = "refreshService", type = "RefreshService | Array")]
+ refresh_service: Option>,
+ /// Terms-of-use specified by the presentation holder.
+ #[typescript(name = "termsOfUse", type = "Policy | Array")]
+ terms_of_use: Option>,
+ /// Miscellaneous properties.
+ #[serde(flatten)]
+ #[typescript(optional = false, name = "[properties: string]", type = "unknown")]
+ properties: Object,
+}
diff --git a/bindings/wasm/src/credential/jwt_presentation/mod.rs b/bindings/wasm/src/credential/jwt_presentation/mod.rs
new file mode 100644
index 0000000000..3f4bb3b90c
--- /dev/null
+++ b/bindings/wasm/src/credential/jwt_presentation/mod.rs
@@ -0,0 +1,7 @@
+// Copyright 2020-2023 IOTA Stiftung
+// SPDX-License-Identifier: Apache-2.0
+
+mod jwt_presentation;
+mod jwt_presentation_builder;
+
+pub use self::jwt_presentation::*;
diff --git a/bindings/wasm/src/credential/jwt_presentation_validation/decoded_jwt_presentation.rs b/bindings/wasm/src/credential/jwt_presentation_validation/decoded_jwt_presentation.rs
new file mode 100644
index 0000000000..71ae171405
--- /dev/null
+++ b/bindings/wasm/src/credential/jwt_presentation_validation/decoded_jwt_presentation.rs
@@ -0,0 +1,79 @@
+// Copyright 2020-2023 IOTA Stiftung
+// SPDX-License-Identifier: Apache-2.0
+
+use identity_iota::credential::DecodedJwtPresentation;
+use wasm_bindgen::prelude::*;
+
+use crate::common::WasmTimestamp;
+use crate::credential::jwt_presentation::WasmJwtPresentation;
+use crate::credential::ArrayDecodedJwtCredential;
+use crate::credential::WasmDecodedJwtCredential;
+use crate::jose::WasmJwsHeader;
+
+/// A cryptographically verified and decoded presentation.
+///
+/// Note that having an instance of this type only means the JWS it was constructed from was verified.
+/// It does not imply anything about a potentially present proof property on the presentation itself.
+#[wasm_bindgen(js_name = DecodedJwtPresentation)]
+pub struct WasmDecodedJwtPresentation(pub(crate) DecodedJwtPresentation);
+
+#[wasm_bindgen(js_class = DecodedJwtPresentation)]
+impl WasmDecodedJwtPresentation {
+ #[wasm_bindgen]
+ pub fn presentation(&self) -> WasmJwtPresentation {
+ WasmJwtPresentation(self.0.presentation.clone())
+ }
+
+ /// Returns a copy of the protected header parsed from the decoded JWS.
+ #[wasm_bindgen(js_name = protectedHeader)]
+ pub fn protected_header(&self) -> WasmJwsHeader {
+ WasmJwsHeader(self.0.header.as_ref().clone())
+ }
+
+ /// Consumes the object and returns the decoded presentation.
+ ///
+ /// ### Warning
+ /// This destroys the `DecodedJwtPresentation` object.
+ #[wasm_bindgen(js_name = intoPresentation)]
+ pub fn into_presentation(self) -> WasmJwtPresentation {
+ WasmJwtPresentation(self.0.presentation)
+ }
+
+ /// The expiration date parsed from the JWT claims.
+ #[wasm_bindgen(js_name = expirationDate)]
+ pub fn expiration_date(&self) -> Option {
+ self.0.expiration_date.map(WasmTimestamp::from)
+ }
+
+ /// The issuance date parsed from the JWT claims.
+ #[wasm_bindgen(js_name = "issuanceDate")]
+ pub fn issuance_date(&self) -> Option {
+ self.0.issuance_date.map(WasmTimestamp::from)
+ }
+
+ /// The `aud` property parsed from JWT claims.
+ #[wasm_bindgen]
+ pub fn audience(&self) -> Option {
+ self.0.aud.clone().map(|aud| aud.to_string())
+ }
+
+ /// The credentials included in the presentation (decoded).
+ #[wasm_bindgen(js_name = "credentials")]
+ pub fn credentials(&self) -> ArrayDecodedJwtCredential {
+ self
+ .0
+ .credentials
+ .iter()
+ .cloned()
+ .map(WasmDecodedJwtCredential::from)
+ .map(JsValue::from)
+ .collect::()
+ .unchecked_into::()
+ }
+}
+
+impl From for WasmDecodedJwtPresentation {
+ fn from(decoded_presentation: DecodedJwtPresentation) -> Self {
+ Self(decoded_presentation)
+ }
+}
diff --git a/bindings/wasm/src/credential/jwt_presentation_validation/jwt_presentation_validator.rs b/bindings/wasm/src/credential/jwt_presentation_validation/jwt_presentation_validator.rs
new file mode 100644
index 0000000000..b159bc16b9
--- /dev/null
+++ b/bindings/wasm/src/credential/jwt_presentation_validation/jwt_presentation_validator.rs
@@ -0,0 +1,118 @@
+// Copyright 2020-2023 IOTA Stiftung
+// SPDX-License-Identifier: Apache-2.0
+
+use super::decoded_jwt_presentation::WasmDecodedJwtPresentation;
+use super::options::WasmJwtPresentationValidationOptions;
+use crate::common::ImportedDocumentLock;
+use crate::common::ImportedDocumentReadGuard;
+use crate::credential::jwt_presentation::WasmJwtPresentation;
+use crate::credential::JwtPresentationDids;
+use crate::credential::WasmFailFast;
+use crate::credential::WasmJwt;
+use crate::did::ArrayIToCoreDocument;
+use crate::did::IToCoreDocument;
+use crate::error::Result;
+use crate::error::WasmResult;
+use crate::verification::IJwsVerifier;
+use crate::verification::WasmJwsVerifier;
+use identity_iota::core::Object;
+use identity_iota::core::OneOrMany;
+use identity_iota::credential::JwtPresentationValidator;
+use identity_iota::did::CoreDID;
+use std::collections::BTreeMap;
+use wasm_bindgen::prelude::*;
+
+#[wasm_bindgen(js_name = JwtPresentationValidator, inspectable)]
+pub struct WasmJwtPresentationValidator(JwtPresentationValidator);
+
+#[wasm_bindgen(js_class = JwtPresentationValidator)]
+impl WasmJwtPresentationValidator {
+ /// Creates a new `JwtPresentationValidator`. If a `signature_verifier` is provided it will be used when
+ /// verifying decoded JWS signatures, otherwise the default which is only capable of handling the `EdDSA`
+ /// algorithm will be used.
+ #[wasm_bindgen(constructor)]
+ pub fn new(signature_verifier: Option) -> WasmJwtPresentationValidator {
+ let signature_verifier = WasmJwsVerifier::new(signature_verifier);
+ WasmJwtPresentationValidator(JwtPresentationValidator::with_signature_verifier(signature_verifier))
+ }
+
+ /// Validates a `JwtPresentation`.
+ ///
+ /// The following properties are validated according to `options`:
+ /// - the JWT can be decoded into semantically valid presentation.
+ /// - the expiration and issuance date contained in the JWT claims.
+ /// - the holder's signature.
+ /// - the relationship between the holder and the credential subjects.
+ /// - the signatures and some properties of the constituent credentials (see `CredentialValidator`).
+ ///
+ /// Validation is done with respect to the properties set in `options`.
+ ///
+ /// # Warning
+ /// The lack of an error returned from this method is in of itself not enough to conclude that the presentation can be
+ /// trusted. This section contains more information on additional checks that should be carried out before and after
+ /// calling this method.
+ ///
+ /// ## The state of the supplied DID Documents.
+ /// The caller must ensure that the DID Documents in `holder` and `issuers` are up-to-date.
+ ///
+ /// ## Properties that are not validated
+ /// There are many properties defined in [The Verifiable Credentials Data Model](https://www.w3.org/TR/vc-data-model/) that are **not** validated, such as:
+ /// `credentialStatus`, `type`, `credentialSchema`, `refreshService`, **and more**.
+ /// These should be manually checked after validation, according to your requirements.
+ ///
+ /// # Errors
+ /// An error is returned whenever a validated condition is not satisfied or when decoding fails.
+ #[wasm_bindgen]
+ pub fn validate(
+ &self,
+ presentation_jwt: &WasmJwt,
+ holder: &IToCoreDocument,
+ issuers: &ArrayIToCoreDocument,
+ validation_options: &WasmJwtPresentationValidationOptions,
+ fail_fast: WasmFailFast,
+ ) -> Result {
+ let issuer_locks: Vec = issuers.into();
+ let issuers_guards: Vec> =
+ issuer_locks.iter().map(ImportedDocumentLock::blocking_read).collect();
+
+ let holder_lock = ImportedDocumentLock::from(holder);
+ let holder_guard = holder_lock.blocking_read();
+
+ self
+ .0
+ .validate(
+ &presentation_jwt.0,
+ &holder_guard,
+ &issuers_guards,
+ &validation_options.0,
+ fail_fast.into(),
+ )
+ .map(WasmDecodedJwtPresentation::from)
+ .wasm_result()
+ }
+
+ /// Validates the semantic structure of the `JwtPresentation`.
+ #[wasm_bindgen(js_name = checkStructure)]
+ pub fn check_structure(presentation: &WasmJwtPresentation) -> Result<()> {
+ JwtPresentationValidator::check_structure(&presentation.0).wasm_result()?;
+ Ok(())
+ }
+
+ /// Attempt to extract the holder of the presentation and the issuers of the included
+ /// credentials.
+ ///
+ /// # Errors:
+ /// * If deserialization/decoding of the presentation or any of the constituent credentials
+ /// fails.
+ /// * If the holder or any of the issuers can't be parsed as DIDs.
+ #[wasm_bindgen(js_name = extractDids)]
+ pub fn extract_dids(presentation: &WasmJwt) -> Result {
+ let (holder, issuers) =
+ JwtPresentationValidator::extract_dids::(&presentation.0).wasm_result()?;
+ let mut map = BTreeMap::<&str, OneOrMany>::new();
+ map.insert("holder", OneOrMany::One(holder));
+ map.insert("issuers", OneOrMany::Many(issuers));
+
+ Ok(JsValue::from_serde(&map).wasm_result()?.unchecked_into())
+ }
+}
diff --git a/bindings/wasm/src/credential/jwt_presentation_validation/mod.rs b/bindings/wasm/src/credential/jwt_presentation_validation/mod.rs
new file mode 100644
index 0000000000..12c556852e
--- /dev/null
+++ b/bindings/wasm/src/credential/jwt_presentation_validation/mod.rs
@@ -0,0 +1,10 @@
+// Copyright 2020-2023 IOTA Stiftung
+// SPDX-License-Identifier: Apache-2.0
+
+mod decoded_jwt_presentation;
+mod jwt_presentation_validator;
+mod options;
+
+pub use self::decoded_jwt_presentation::*;
+pub use self::jwt_presentation_validator::*;
+pub use self::options::*;
diff --git a/bindings/wasm/src/credential/jwt_presentation_validation/options.rs b/bindings/wasm/src/credential/jwt_presentation_validation/options.rs
new file mode 100644
index 0000000000..7fd6f4781d
--- /dev/null
+++ b/bindings/wasm/src/credential/jwt_presentation_validation/options.rs
@@ -0,0 +1,85 @@
+// Copyright 2020-2023 IOTA Stiftung
+// SPDX-License-Identifier: Apache-2.0
+
+use crate::error::Result;
+use crate::error::WasmResult;
+use identity_iota::credential::JwtPresentationValidationOptions;
+use wasm_bindgen::prelude::*;
+
+/// Options to declare validation criteria when validating presentation.
+#[wasm_bindgen(js_name = JwtPresentationValidationOptions)]
+pub struct WasmJwtPresentationValidationOptions(pub(crate) JwtPresentationValidationOptions);
+
+#[wasm_bindgen(js_class = JwtPresentationValidationOptions)]
+impl WasmJwtPresentationValidationOptions {
+ /// Creates a new `JwtPresentationValidationOptions` from the given fields.
+ ///
+ /// Throws an error if any of the options are invalid.
+ #[wasm_bindgen(constructor)]
+ pub fn new(options: IJwtPresentationValidationOptions) -> Result {
+ let options: JwtPresentationValidationOptions = options.into_serde().wasm_result()?;
+ Ok(WasmJwtPresentationValidationOptions::from(options))
+ }
+
+ /// Creates a new `JwtPresentationValidationOptions` with defaults.
+ #[allow(clippy::should_implement_trait)]
+ #[wasm_bindgen]
+ pub fn default() -> WasmJwtPresentationValidationOptions {
+ WasmJwtPresentationValidationOptions::from(JwtPresentationValidationOptions::default())
+ }
+}
+
+impl_wasm_json!(WasmJwtPresentationValidationOptions, JwtPresentationValidationOptions);
+impl_wasm_clone!(WasmJwtPresentationValidationOptions, JwtPresentationValidationOptions);
+
+impl From for WasmJwtPresentationValidationOptions {
+ fn from(options: JwtPresentationValidationOptions) -> Self {
+ Self(options)
+ }
+}
+
+impl From for JwtPresentationValidationOptions {
+ fn from(options: WasmJwtPresentationValidationOptions) -> Self {
+ options.0
+ }
+}
+
+#[wasm_bindgen]
+extern "C" {
+ #[wasm_bindgen(typescript_type = "IJwtPresentationValidationOptions")]
+ pub type IJwtPresentationValidationOptions;
+}
+
+#[wasm_bindgen(typescript_custom_section)]
+const I_JWT_PRESENTATION_VALIDATION_OPTIONS: &'static str = r#"
+/** Holds options to create a new `JwtPresentationValidationOptions`. */
+interface IJwtPresentationValidationOptions {
+ /**
+ * Options which affect the validation of *all* credentials in the presentation.
+ */
+ readonly sharedValidationOptions?: JwtCredentialValidationOptions;
+
+ /**
+ * Options which affect the verification of the signature on the presentation.
+ */
+ readonly presentationVerifierOptions?: JwsVerificationOptions;
+
+ /**
+ * Declare how the presentation's credential subjects must relate to the holder.
+ *
+ * Default: `SubjectHolderRelationship.AlwaysSubject`
+ */
+ readonly subjectHolderRelationship?: SubjectHolderRelationship;
+
+ /**
+ * Declare that the presentation is **not** considered valid if it expires before this `Timestamp`.
+ * Uses the current datetime during validation if not set.
+ */
+ readonly earliestExpiryDate?: Timestamp;
+
+ /**
+ * Declare that the presentation is **not** considered valid if it was issued later than this `Timestamp`.
+ * Uses the current datetime during validation if not set.
+ */
+ readonly latestIssuanceDate?: Timestamp;
+}"#;
diff --git a/bindings/wasm/src/credential/mod.rs b/bindings/wasm/src/credential/mod.rs
index c5e562d143..63b6654d2f 100644
--- a/bindings/wasm/src/credential/mod.rs
+++ b/bindings/wasm/src/credential/mod.rs
@@ -1,4 +1,4 @@
-// Copyright 2020-2022 IOTA Stiftung
+// Copyright 2020-2023 IOTA Stiftung
// SPDX-License-Identifier: Apache-2.0
#![allow(clippy::module_inception)]
@@ -10,6 +10,8 @@ pub use self::domain_linkage_configuration::WasmDomainLinkageConfiguration;
pub use self::jws::WasmJws;
pub use self::jwt::WasmJwt;
pub use self::jwt_credential_validation::*;
+pub use self::jwt_presentation::*;
+pub use self::jwt_presentation_validation::*;
pub use self::presentation::WasmPresentation;
pub use self::presentation_builder::*;
pub use self::presentation_validator::WasmPresentationValidator;
@@ -28,6 +30,8 @@ mod domain_linkage_validator;
mod jws;
mod jwt;
mod jwt_credential_validation;
+mod jwt_presentation;
+mod jwt_presentation_validation;
mod linked_domain_service;
mod presentation;
mod presentation_builder;
diff --git a/bindings/wasm/src/credential/types.rs b/bindings/wasm/src/credential/types.rs
index 54c94c86b9..615d4c0441 100644
--- a/bindings/wasm/src/credential/types.rs
+++ b/bindings/wasm/src/credential/types.rs
@@ -31,6 +31,18 @@ extern "C" {
#[wasm_bindgen(typescript_type = "Array")]
pub type ArrayCredential;
+
+ #[wasm_bindgen(typescript_type = "Array")]
+ pub type ArrayDecodedJwtCredential;
+
+ #[wasm_bindgen(typescript_type = "Array")]
+ pub type ArrayJwt;
+
+ #[wasm_bindgen(typescript_type = "Array")]
+ pub type ArrayCoreDID;
+
+ #[wasm_bindgen(typescript_type = "JwtPresentationDids")]
+ pub type JwtPresentationDids;
}
#[wasm_bindgen(typescript_custom_section)]
@@ -126,3 +138,19 @@ interface Subject {
/** Additional properties of the credential subject. */
readonly [properties: string]: unknown;
}"#;
+
+#[wasm_bindgen(typescript_custom_section)]
+const I_JWT_PRESENTATOIN_DIDS: &'static str = r#"
+/**
+ * DIDs of the presentation holder and the issuers of the contained credentials.
+ */
+interface JwtPresentationDids {
+ /**
+ * Presentation holder.
+ */
+ holder: CoreDID;
+ /**
+ * Issuers of the verifiable credentials contained in the presentation.
+ */
+ issuers: Array;
+}"#;
diff --git a/bindings/wasm/src/did/wasm_core_document.rs b/bindings/wasm/src/did/wasm_core_document.rs
index 99683450fd..6b0150692b 100644
--- a/bindings/wasm/src/did/wasm_core_document.rs
+++ b/bindings/wasm/src/did/wasm_core_document.rs
@@ -18,6 +18,7 @@ use crate::common::UOneOrManyNumber;
use crate::credential::WasmCredential;
use crate::credential::WasmJws;
use crate::credential::WasmJwt;
+use crate::credential::WasmJwtPresentation;
use crate::crypto::WasmProofOptions;
use crate::did::service::WasmService;
use crate::did::wasm_did_url::WasmDIDUrl;
@@ -27,6 +28,7 @@ use crate::error::WasmResult;
use crate::jose::WasmDecodedJws;
use crate::jose::WasmJwsAlgorithm;
use crate::storage::WasmJwsSignatureOptions;
+use crate::storage::WasmJwtPresentationOptions;
use crate::storage::WasmStorage;
use crate::storage::WasmStorageInner;
use crate::verification::IJwsVerifier;
@@ -41,6 +43,8 @@ use identity_iota::core::OneOrSet;
use identity_iota::core::OrderedSet;
use identity_iota::core::Url;
use identity_iota::credential::Credential;
+use identity_iota::credential::JwtPresentation;
+use identity_iota::credential::JwtPresentationOptions;
use identity_iota::credential::RevocationDocumentExt;
use identity_iota::crypto::PrivateKey;
use identity_iota::crypto::ProofOptions;
@@ -702,13 +706,11 @@ impl WasmCoreDocument {
Ok(promise.unchecked_into())
}
- /// Produces a JWS where the payload is produced from the given `credential`
+ /// Produces a JWT where the payload is produced from the given `credential`
/// in accordance with [VC-JWT version 1.1.](https://w3c.github.io/vc-jwt/#version-1.1).
///
/// The `kid` in the protected header is the `id` of the method identified by `fragment` and the JWS signature will be
/// produced by the corresponding private key backed by the `storage` in accordance with the passed `options`.
- // TODO: Perhaps this should be called `signCredential` (and the old `signCredential` method would have to be updated
- // or removed)?
#[wasm_bindgen(js_name = createCredentialJwt)]
pub fn create_credential_jwt(
&self,
@@ -733,6 +735,44 @@ impl WasmCoreDocument {
});
Ok(promise.unchecked_into())
}
+
+ /// Produces a JWT where the payload is produced from the given presentation.
+ /// in accordance with [VC-JWT version 1.1](https://w3c.github.io/vc-jwt/#version-1.1).
+ ///
+ /// The `kid` in the protected header is the `id` of the method identified by `fragment` and the JWS signature will be
+ /// produced by the corresponding private key backed by the `storage` in accordance with the passed `options`.
+ #[wasm_bindgen(js_name = createPresentationJwt)]
+ pub fn create_presentation_jwt(
+ &self,
+ storage: &WasmStorage,
+ fragment: String,
+ presentation: &WasmJwtPresentation,
+ signature_options: &WasmJwsSignatureOptions,
+ presentation_options: &WasmJwtPresentationOptions,
+ ) -> Result {
+ let storage_clone: Rc = storage.0.clone();
+ let options_clone: JwsSignatureOptions = signature_options.0.clone();
+ let document_lock_clone: Rc = self.0.clone();
+ let presentation_clone: JwtPresentation = presentation.0.clone();
+ let presentation_options_clone: JwtPresentationOptions = presentation_options.0.clone();
+ let promise: Promise = future_to_promise(async move {
+ document_lock_clone
+ .read()
+ .await
+ .sign_presentation(
+ &presentation_clone,
+ &storage_clone,
+ &fragment,
+ &options_clone,
+ &presentation_options_clone,
+ )
+ .await
+ .wasm_result()
+ .map(WasmJwt::new)
+ .map(JsValue::from)
+ });
+ Ok(promise.unchecked_into())
+ }
}
#[wasm_bindgen]
diff --git a/bindings/wasm/src/error.rs b/bindings/wasm/src/error.rs
index 122f2b0cf9..a345af664a 100644
--- a/bindings/wasm/src/error.rs
+++ b/bindings/wasm/src/error.rs
@@ -1,6 +1,7 @@
// Copyright 2020-2023 IOTA Stiftung
// SPDX-License-Identifier: Apache-2.0
+use identity_iota::credential::CompoundJwtPresentationValidationError;
use identity_iota::resolver;
use identity_iota::storage::key_id_storage::KeyIdStorageError;
use identity_iota::storage::key_id_storage::KeyIdStorageErrorKind;
@@ -259,6 +260,15 @@ impl From for WasmError<'_> {
+ fn from(error: CompoundJwtPresentationValidationError) -> Self {
+ Self {
+ name: Cow::Borrowed("CompoundJwtPresentationValidationError"),
+ message: Cow::Owned(ErrorMessage(&error).to_string()),
+ }
+ }
+}
+
/// Convenience struct to convert Result to errors in the Rust library.
pub struct JsValueResult(pub(crate) Result);
diff --git a/bindings/wasm/src/iota/iota_document.rs b/bindings/wasm/src/iota/iota_document.rs
index 5f21d0d465..ff965ef8b0 100644
--- a/bindings/wasm/src/iota/iota_document.rs
+++ b/bindings/wasm/src/iota/iota_document.rs
@@ -8,6 +8,8 @@ use identity_iota::core::OrderedSet;
use identity_iota::core::Timestamp;
use identity_iota::core::Url;
use identity_iota::credential::Credential;
+use identity_iota::credential::JwtPresentation;
+use identity_iota::credential::JwtPresentationOptions;
use identity_iota::credential::Presentation;
use identity_iota::crypto::PrivateKey;
use identity_iota::crypto::ProofOptions;
@@ -46,6 +48,7 @@ use crate::common::WasmTimestamp;
use crate::credential::WasmCredential;
use crate::credential::WasmJws;
use crate::credential::WasmJwt;
+use crate::credential::WasmJwtPresentation;
use crate::credential::WasmPresentation;
use crate::crypto::WasmProofOptions;
use crate::did::CoreDocumentLock;
@@ -65,6 +68,7 @@ use crate::iota::WasmStateMetadataEncoding;
use crate::jose::WasmDecodedJws;
use crate::jose::WasmJwsAlgorithm;
use crate::storage::WasmJwsSignatureOptions;
+use crate::storage::WasmJwtPresentationOptions;
use crate::storage::WasmStorage;
use crate::storage::WasmStorageInner;
use crate::verification::IJwsVerifier;
@@ -827,8 +831,6 @@ impl WasmIotaDocument {
///
/// The `kid` in the protected header is the `id` of the method identified by `fragment` and the JWS signature will be
/// produced by the corresponding private key backed by the `storage` in accordance with the passed `options`.
- // TODO: Perhaps this should be called `signCredential` (and the old `signCredential` method would have to be updated
- // or removed)?
#[wasm_bindgen(js_name = createCredentialJwt)]
pub fn create_credential_jwt(
&self,
@@ -853,6 +855,44 @@ impl WasmIotaDocument {
});
Ok(promise.unchecked_into())
}
+
+ /// Produces a JWT where the payload is produced from the given presentation.
+ /// in accordance with [VC-JWT version 1.1](https://w3c.github.io/vc-jwt/#version-1.1).
+ ///
+ /// The `kid` in the protected header is the `id` of the method identified by `fragment` and the JWS signature will be
+ /// produced by the corresponding private key backed by the `storage` in accordance with the passed `options`.
+ #[wasm_bindgen(js_name = createPresentationJwt)]
+ pub fn create_presentation_jwt(
+ &self,
+ storage: &WasmStorage,
+ fragment: String,
+ presentation: &WasmJwtPresentation,
+ signature_options: &WasmJwsSignatureOptions,
+ presentation_options: &WasmJwtPresentationOptions,
+ ) -> Result {
+ let storage_clone: Rc = storage.0.clone();
+ let options_clone: JwsSignatureOptions = signature_options.0.clone();
+ let document_lock_clone: Rc = self.0.clone();
+ let presentation_clone: JwtPresentation = presentation.0.clone();
+ let presentation_options_clone: JwtPresentationOptions = presentation_options.0.clone();
+ let promise: Promise = future_to_promise(async move {
+ document_lock_clone
+ .read()
+ .await
+ .sign_presentation(
+ &presentation_clone,
+ &storage_clone,
+ &fragment,
+ &options_clone,
+ &presentation_options_clone,
+ )
+ .await
+ .wasm_result()
+ .map(WasmJwt::new)
+ .map(JsValue::from)
+ });
+ Ok(promise.unchecked_into())
+ }
}
impl From for WasmIotaDocument {
diff --git a/bindings/wasm/src/storage/jwt_presentation_options.rs b/bindings/wasm/src/storage/jwt_presentation_options.rs
new file mode 100644
index 0000000000..ef41c6ff3a
--- /dev/null
+++ b/bindings/wasm/src/storage/jwt_presentation_options.rs
@@ -0,0 +1,81 @@
+// Copyright 2020-2023 IOTA Stiftung
+// SPDX-License-Identifier: Apache-2.0
+
+use crate::error::Result;
+use crate::error::WasmResult;
+use identity_iota::credential::JwtPresentationOptions;
+use wasm_bindgen::prelude::*;
+
+#[wasm_bindgen(js_name = JwtPresentationOptions)]
+pub struct WasmJwtPresentationOptions(pub(crate) JwtPresentationOptions);
+
+#[wasm_bindgen(js_class = JwtPresentationOptions)]
+impl WasmJwtPresentationOptions {
+ /// Creates a new `JwtPresentationOptions` from the given fields.
+ ///
+ /// Throws an error if any of the options are invalid.
+ #[wasm_bindgen(constructor)]
+ pub fn new(options: Option) -> Result {
+ if let Some(options) = options {
+ let options: JwtPresentationOptions = options.into_serde().wasm_result()?;
+ Ok(WasmJwtPresentationOptions::from(options))
+ } else {
+ Ok(WasmJwtPresentationOptions::from(JwtPresentationOptions::default()))
+ }
+ }
+
+ /// Creates a new `JwtPresentationOptions` with defaults.
+ #[allow(clippy::should_implement_trait)]
+ #[wasm_bindgen]
+ pub fn default() -> WasmJwtPresentationOptions {
+ WasmJwtPresentationOptions::from(JwtPresentationOptions::default())
+ }
+}
+
+impl_wasm_json!(WasmJwtPresentationOptions, JwtPresentationOptions);
+impl_wasm_clone!(WasmJwtPresentationOptions, JwtPresentationOptions);
+
+impl From for WasmJwtPresentationOptions {
+ fn from(options: JwtPresentationOptions) -> Self {
+ Self(options)
+ }
+}
+
+impl From for JwtPresentationOptions {
+ fn from(options: WasmJwtPresentationOptions) -> Self {
+ options.0
+ }
+}
+
+#[wasm_bindgen]
+extern "C" {
+ #[wasm_bindgen(typescript_type = "IJwtPresentationOptions")]
+ pub type IJwtPresentationOptions;
+}
+
+#[wasm_bindgen(typescript_custom_section)]
+const I_JWT_PRESENTATION_OPTIONS: &'static str = r#"
+/** Options to be set in the JWT claims of a verifiable presentation. */
+interface IJwtPresentationOptions {
+ /**
+ * Set the presentation's expiration date.
+ * Default: `undefined`.
+ **/
+ readonly expirationDate?: Timestamp;
+
+ /**
+ * Set the presentation's issuance date.
+ * Default: current datetime.
+ */
+ readonly issuanceDate?: Timestamp;
+
+ /**
+ * Sets the audience for presentation (`aud` property in JWT claims).
+ *
+ * ## Note:
+ * Value must be a valid URL.
+ *
+ * Default: `undefined`.
+ */
+ readonly audience?: string;
+}"#;
diff --git a/bindings/wasm/src/storage/mod.rs b/bindings/wasm/src/storage/mod.rs
index 88a36f4c04..8295d95e88 100644
--- a/bindings/wasm/src/storage/mod.rs
+++ b/bindings/wasm/src/storage/mod.rs
@@ -3,6 +3,7 @@
mod jwk_gen_output;
mod jwk_storage;
+mod jwt_presentation_options;
mod key_id_storage;
mod method_digest;
mod signature_options;
@@ -10,6 +11,7 @@ mod wasm_storage;
pub use jwk_gen_output::*;
pub use jwk_storage::*;
+pub use jwt_presentation_options::*;
pub use key_id_storage::*;
pub use method_digest::*;
pub use signature_options::*;
diff --git a/bindings/wasm/tests/storage.ts b/bindings/wasm/tests/storage.ts
index 100132839b..d9c3b1dd4a 100644
--- a/bindings/wasm/tests/storage.ts
+++ b/bindings/wasm/tests/storage.ts
@@ -1,8 +1,9 @@
const assert = require("assert");
-import { RandomHelper } from "@iota/util.js";
import {
CoreDocument,
Credential,
+ DecodedJwtPresentation,
+ Duration,
FailFast,
IJwsVerifier,
IotaDocument,
@@ -10,11 +11,17 @@ import {
JwsAlgorithm,
JwsSignatureOptions,
JwsVerificationOptions,
+ Jwt,
JwtCredentialValidationOptions,
JwtCredentialValidator,
+ JwtPresentation,
+ JwtPresentationOptions,
+ JwtPresentationValidationOptions,
+ JwtPresentationValidator,
MethodDigest,
MethodScope,
Storage,
+ Timestamp,
VerificationMethod,
verifyEdDSA,
} from "../node";
@@ -109,30 +116,23 @@ describe("#JwkStorageDocument", function() {
// Check that the credentialJwt can be decoded and verified
let credentialValidator = new JwtCredentialValidator();
- const credentialRetrieved = credentialValidator.validate(
- credentialJwt,
- doc,
- JwtCredentialValidationOptions.default(),
- FailFast.FirstError,
- ).credential();
+ const credentialRetrieved = credentialValidator
+ .validate(credentialJwt, doc, JwtCredentialValidationOptions.default(), FailFast.FirstError)
+ .credential();
assert.deepStrictEqual(credentialRetrieved.toJSON(), credential.toJSON());
// Also check using our custom verifier
let credentialValidatorCustom = new JwtCredentialValidator(customVerifier);
- const credentialRetrievedCustom = credentialValidatorCustom.validate(
- credentialJwt,
- doc,
- JwtCredentialValidationOptions.default(),
- FailFast.AllErrors,
- ).credential();
+ const credentialRetrievedCustom = credentialValidatorCustom
+ .validate(credentialJwt, doc, JwtCredentialValidationOptions.default(), FailFast.AllErrors)
+ .credential();
// Check that customVerifer.verify was indeed called
assert.deepStrictEqual(customVerifier.verifications(), 2);
assert.deepStrictEqual(credentialRetrievedCustom.toJSON(), credential.toJSON());
// Delete the method
const methodId = (method as VerificationMethod).id();
- await doc.purgeMethod(storage, methodId);
- // Check that the method can no longer be resolved.
+ await doc.purgeMethod(storage, methodId); // Check that the method can no longer be resolved.
assert.deepStrictEqual(doc.resolveMethod(fragment), undefined);
// The storage should now be empty
assert.deepStrictEqual((storage.keyIdStorage() as KeyIdMemStore).count(), 0);
@@ -186,58 +186,132 @@ describe("#JwkStorageDocument", function() {
issuer: doc.id(),
issuanceDate: "2010-01-01T00:00:00Z",
};
+ });
+
+ it("JwtPresentation should work", async () => {
+ const keystore = new JwkMemStore();
+ const keyIdStore = new KeyIdMemStore();
+ const storage = new Storage(keystore, keyIdStore);
+ const issuerDoc = new IotaDocument("tst1");
+ const fragment = "#key-1";
+ await issuerDoc.generateMethod(
+ storage,
+ JwkMemStore.ed25519KeyType(),
+ JwsAlgorithm.EdDSA,
+ fragment,
+ MethodScope.VerificationMethod(),
+ );
+
+ const holderDoc = new IotaDocument("tst2");
+ await holderDoc.generateMethod(
+ storage,
+ JwkMemStore.ed25519KeyType(),
+ JwsAlgorithm.EdDSA,
+ fragment,
+ MethodScope.VerificationMethod(),
+ );
+
+ let customVerifier = new CustomVerifier();
+ const credentialFields = {
+ context: "https://www.w3.org/2018/credentials/examples/v1",
+ id: "https://example.edu/credentials/3732",
+ type: "UniversityDegreeCredential",
+ credentialSubject: {
+ id: holderDoc.id(),
+ degree: {
+ type: "BachelorDegree",
+ name: "Bachelor of Science and Arts",
+ },
+ },
+ issuer: issuerDoc.id(),
+ issuanceDate: Timestamp.nowUTC(),
+ };
const credential = new Credential(credentialFields);
- // Create the JWT
- const credentialJwt = await doc.createCredentialJwt(storage, fragment, credential, new JwsSignatureOptions());
+ const credentialJwt: Jwt = await issuerDoc.createCredentialJwt(
+ storage,
+ fragment,
+ credential,
+ new JwsSignatureOptions(),
+ );
- // Check that the credentialJwt can be decoded and verified
- let credentialValidator = new JwtCredentialValidator();
- const credentialRetrieved = credentialValidator.validate(
- credentialJwt,
- doc,
- JwtCredentialValidationOptions.default(),
+ const presentation = new JwtPresentation({
+ holder: holderDoc.id(),
+ verifiableCredential: [credentialJwt.toString(), credentialJwt.toString()],
+ });
+
+ const expirationDate = Timestamp.nowUTC().checkedAdd(Duration.days(2));
+ const audience = "did:test:123";
+ const presentationJwt = await holderDoc.createPresentationJwt(
+ storage,
+ fragment,
+ presentation,
+ new JwsSignatureOptions(),
+ new JwtPresentationOptions({
+ expirationDate,
+ issuanceDate: Timestamp.nowUTC(),
+ audience,
+ }),
+ );
+
+ let validator = new JwtPresentationValidator(customVerifier);
+ let decoded: DecodedJwtPresentation = validator.validate(
+ presentationJwt,
+ holderDoc,
+ [issuerDoc],
+ JwtPresentationValidationOptions.default(),
FailFast.FirstError,
- ).credential();
- assert.deepStrictEqual(credentialRetrieved.toJSON(), credential.toJSON());
+ );
- // Also check using our custom verifier
- let credentialValidatorCustom = new JwtCredentialValidator(customVerifier);
- const credentialRetrievedCustom = credentialValidatorCustom.validate(
- credentialJwt,
- doc,
- JwtCredentialValidationOptions.default(),
- FailFast.AllErrors,
- ).credential();
- // Check that customVerifer.verify was indeed called
- assert.deepStrictEqual(customVerifier.verifications(), 2);
- assert.deepStrictEqual(credentialRetrievedCustom.toJSON(), credential.toJSON());
+ assert.deepStrictEqual(decoded.credentials()[0].credential().toJSON(), credential.toJSON());
+ assert.equal(decoded.expirationDate()!.toString(), expirationDate!.toString());
+ assert.deepStrictEqual(decoded.presentation().toJSON(), presentation.toJSON());
+ assert.equal(decoded.audience(), audience);
- // Delete the method
- const methodId = (method as VerificationMethod).id();
- await doc.purgeMethod(storage, methodId);
- // Check that the method can no longer be resolved.
- assert.deepStrictEqual(doc.resolveMethod(fragment), undefined);
- // The storage should now be empty
- assert.deepStrictEqual((storage.keyIdStorage() as KeyIdMemStore).count(), 0);
- assert.deepStrictEqual((storage.keyStorage() as JwkMemStore).count(), 0);
+ // check issuance date validation.
+ let options = new JwtPresentationValidationOptions({
+ latestIssuanceDate: Timestamp.nowUTC().checkedSub(Duration.days(1)),
+ });
+ assert.throws(() => {
+ validator.validate(presentationJwt, holderDoc, [issuerDoc], options, FailFast.FirstError);
+ });
+
+ // Check expiration date validation.
+ options = new JwtPresentationValidationOptions({
+ earliestExpiryDate: Timestamp.nowUTC().checkedAdd(Duration.days(1)),
+ });
+ validator.validate(presentationJwt, holderDoc, [issuerDoc], options, FailFast.FirstError);
+
+ options = new JwtPresentationValidationOptions({
+ earliestExpiryDate: Timestamp.nowUTC().checkedAdd(Duration.days(3)),
+ });
+ assert.throws(() => {
+ validator.validate(presentationJwt, holderDoc, [issuerDoc], options, FailFast.FirstError);
+ });
+
+ // Check `extractDids`.
+ let presentationDids = JwtPresentationValidator.extractDids(presentationJwt);
+ assert.equal(presentationDids.holder.toString(), holderDoc.id().toString());
+ assert.equal(presentationDids.issuers.length, 2);
+ assert.equal(presentationDids.issuers[0].toString(), issuerDoc.id().toString());
+ assert.equal(presentationDids.issuers[1].toString(), issuerDoc.id().toString());
});
-});
-class CustomVerifier implements IJwsVerifier {
- private _verifications: number;
+ class CustomVerifier implements IJwsVerifier {
+ private _verifications: number;
- constructor() {
- this._verifications = 0;
- }
+ constructor() {
+ this._verifications = 0;
+ }
- public verifications(): number {
- return this._verifications;
- }
+ public verifications(): number {
+ return this._verifications;
+ }
- public verify(alg: JwsAlgorithm, signingInput: Uint8Array, decodedSignature: Uint8Array, publicKey: Jwk): void {
- verifyEdDSA(alg, signingInput, decodedSignature, publicKey);
- this._verifications += 1;
- return;
+ public verify(alg: JwsAlgorithm, signingInput: Uint8Array, decodedSignature: Uint8Array, publicKey: Jwk): void {
+ verifyEdDSA(alg, signingInput, decodedSignature, publicKey);
+ this._verifications += 1;
+ return;
+ }
}
-}
+});
diff --git a/identity_credential/src/presentation/jwt_presentation_options.rs b/identity_credential/src/presentation/jwt_presentation_options.rs
index 925ffe0812..926d4621a4 100644
--- a/identity_credential/src/presentation/jwt_presentation_options.rs
+++ b/identity_credential/src/presentation/jwt_presentation_options.rs
@@ -5,7 +5,8 @@ use identity_core::common::Timestamp;
use identity_core::common::Url;
/// Options to be set in the JWT claims of a verifiable presentation.
-#[derive(Clone, Debug)]
+#[derive(Clone, Debug, Serialize, Deserialize)]
+#[serde(rename_all = "camelCase")]
pub struct JwtPresentationOptions {
/// Set the presentation's expiration date.
/// Default: `None`.
diff --git a/identity_credential/src/validator/vp_jwt_validation/decoded_jwt_presentation.rs b/identity_credential/src/validator/vp_jwt_validation/decoded_jwt_presentation.rs
index c81c6a1130..d84c5130bb 100644
--- a/identity_credential/src/validator/vp_jwt_validation/decoded_jwt_presentation.rs
+++ b/identity_credential/src/validator/vp_jwt_validation/decoded_jwt_presentation.rs
@@ -22,7 +22,7 @@ pub struct DecodedJwtPresentation {
pub header: Box,
/// The expiration date parsed from the JWT claims.
pub expiration_date: Option,
- /// The issuance dated parsed from the JWT claims.
+ /// The issuance date parsed from the JWT claims.
pub issuance_date: Option,
/// The `aud` property parsed from the JWT claims.
pub aud: Option,
diff --git a/identity_credential/src/validator/vp_jwt_validation/jwt_presentation_validator.rs b/identity_credential/src/validator/vp_jwt_validation/jwt_presentation_validator.rs
index 595e6a8f95..605a7aa5a4 100644
--- a/identity_credential/src/validator/vp_jwt_validation/jwt_presentation_validator.rs
+++ b/identity_credential/src/validator/vp_jwt_validation/jwt_presentation_validator.rs
@@ -195,13 +195,6 @@ where
Ok(decoded_jwt_presentation)
}
- /// Validates the semantic structure of the `JwtPresentation`.
- pub fn check_structure(presentation: &JwtPresentation) -> Result<(), ValidationError> {
- presentation
- .check_structure()
- .map_err(ValidationError::PresentationStructure)
- }
-
fn validate_credentials(
&self,
presentation: &JwtPresentation,
@@ -291,4 +284,11 @@ impl JwtPresentationValidator {
}
Ok((holder, issuers))
}
+
+ /// Validates the semantic structure of the `JwtPresentation`.
+ pub fn check_structure(presentation: &JwtPresentation) -> Result<(), ValidationError> {
+ presentation
+ .check_structure()
+ .map_err(ValidationError::PresentationStructure)
+ }
}
diff --git a/identity_storage/src/storage/jwk_document_ext.rs b/identity_storage/src/storage/jwk_document_ext.rs
index ade03d8b63..2177a9139a 100644
--- a/identity_storage/src/storage/jwk_document_ext.rs
+++ b/identity_storage/src/storage/jwk_document_ext.rs
@@ -81,7 +81,7 @@ pub trait JwkDocumentExt: private::Sealed {
K: JwkStorage,
I: KeyIdStorage;
- /// Produces a JWS where the payload is produced from the given `credential`
+ /// Produces a JWT where the payload is produced from the given `credential`
/// in accordance with [VC-JWT version 1.1.](https://w3c.github.io/vc-jwt/#version-1.1).
///
/// The `kid` in the protected header is the `id` of the method identified by `fragment` and the JWS signature will be
@@ -98,7 +98,7 @@ pub trait JwkDocumentExt: private::Sealed {
I: KeyIdStorage,
T: ToOwned + Serialize + DeserializeOwned + Sync;
- /// Produces a JWS where the payload is produced from the given `presentation`
+ /// Produces a JWT where the payload is produced from the given `presentation`
/// in accordance with [VC-JWT version 1.1](https://w3c.github.io/vc-jwt/#version-1.1).
///
/// The `kid` in the protected header is the `id` of the method identified by `fragment` and the JWS signature will be