sd-jwt-0.1.0.0: Selective Disclosure for JSON Web Tokens (RFC 9901)
Safe HaskellNone
LanguageHaskell2010

SDJWT.Holder

Description

Convenience module for SD-JWT holders.

This module provides everything needed to receive SD-JWTs and create presentations. It exports a focused API for the holder role, excluding modules that holders don't need (like Issuance and Verification).

Usage

For holders, import this module:

import SDJWT.Holder

This gives you access to:

Creating Presentations

The main workflow for holders is:

-- 1. Deserialize SD-JWT received from issuer
case deserializeSDJWT sdjwtText of
  Right sdjwt -> do
    -- 2. Select which disclosures to include
    -- Examples of different selection patterns:
    --   Top-level claims: ["given_name", "email"]
    --   Nested object claims: ["address/street_address", "address/locality"]
    --   Array elements: ["nationalities/0", "nationalities/2"]
    --   Mixed paths: ["address/street_address", "nationalities/1"]
    case selectDisclosuresByNames sdjwt ["given_name", "email"] of
      Right presentation -> do
        -- 3. Optionally add key binding for proof of possession
        holderPrivateKeyJWK <- loadPrivateKeyJWK
        let audience = "verifier.example.com"
        let nonce = "random-nonce-12345"
        let issuedAt = 1683000000 :: Int64
        -- Optional: Add standard JWT claims like exp (expiration time) to KB-JWT
        -- These claims will be automatically validated during verification if present
        let expirationTime = issuedAt + 3600  -- 1 hour from issued time
        let optionalClaims = Aeson.object [("exp", Aeson.Number (fromIntegral expirationTime))]
        kbResult <- addKeyBindingToPresentation SHA256 holderPrivateKeyJWK audience nonce issuedAt presentation optionalClaims
        case kbResult of
          Right presentationWithKB -> do
            -- 4. Serialize presentation to send to verifier
            let serialized = serializePresentation presentationWithKB
            -- Send serialized presentation...
          Left err -> -- Handle error
      Left err -> -- Handle error
  Left err -> -- Handle error

Optional Claims in KB-JWT

The optionalClaims parameter allows adding standard JWT claims (RFC 7519) to the KB-JWT, such as exp (expiration time) or nbf (not before). These claims will be automatically validated during verification if present. Pass Aeson.object [] for no additional claims. Note: RFC 9901 Section 4.3 states that additional claims SHOULD be avoided unless there is a compelling reason, as they may harm interoperability.

For advanced use cases (e.g., creating presentations manually or computing SD hash separately), import Presentation or KeyBinding to access additional low-level functions.

Synopsis

Core Types

Serialization

deserializeSDJWT :: Text -> Either SDJWTError SDJWT Source #

Deserialize SD-JWT from tilde-separated format.

Parses a tilde-separated string into an SDJWT structure. Returns an error if the format is invalid or if a Key Binding JWT is present (use deserializePresentation for SD-JWT+KB).

serializePresentation :: SDJWTPresentation -> Text Source #

Serialize SD-JWT presentation.

Format: JWT~1~...~N~[KB-JWT]

If a Key Binding JWT is present, it is included as the last component. Otherwise, the last component is empty (just a trailing tilde).

Presentation

Functions for creating SD-JWT presentations with selected disclosures.

selectDisclosuresByNames Source #

Arguments

:: SDJWT 
-> [Text]

Claim names to include in presentation (supports JSON Pointer syntax for nested paths, including array indices)

-> Either SDJWTError SDJWTPresentation 

Select disclosures from an SD-JWT based on claim names.

This function:

  1. Decodes all disclosures from the SD-JWT
  2. Filters disclosures to include only those matching the provided claim names
  3. Handles recursive disclosures (Section 6.3): when selecting nested claims, automatically includes parent disclosures if they are recursively disclosable
  4. Validates disclosure dependencies (ensures all required parent disclosures are present)
  5. Returns a presentation with the selected disclosures

Note: This function validates that the selected disclosures exist in the SD-JWT. Supports JSON Pointer syntax for nested paths:

  • Object properties: ["address/street_address", "address/locality"]
  • Array elements: ["nationalities/0", "nationalities/2"]
  • Mixed paths: ["address/street_address", "nationalities/1"]
  • Nested arrays: ["nested_array/0/0", "nested_array/1/1"]

Paths with numeric segments (e.g., ["x/22"]) are resolved by checking the actual claim type: if x is an array, it refers to index 22; if x is an object, it refers to property "22".

Key Binding

Functions for adding key binding to presentations (SD-JWT+KB).

addKeyBindingToPresentation Source #

Arguments

:: JWKLike jwk 
=> HashAlgorithm

Hash algorithm for computing sd_hash

-> jwk

Holder private key (Text or jose JWK object)

-> Text

Audience claim (verifier identifier)

-> Text

Nonce provided by verifier

-> Int64

Issued at timestamp (Unix epoch seconds)

-> SDJWTPresentation

The SD-JWT presentation to bind

-> Object

Optional additional claims (e.g., exp, nbf). Standard JWT claims will be validated during verification if present. Pass KeyMap.empty for no additional claims.

-> IO (Either SDJWTError SDJWTPresentation) 

Add key binding to a presentation.

Creates a KB-JWT and adds it to the presentation, converting it to SD-JWT+KB format. The KB-JWT includes required claims (aud, nonce, iat, sd_hash) plus any optional claims provided. Standard JWT claims like exp (expiration time) and nbf (not before) will be automatically validated during verification if present.

Note: RFC 9901 Section 4.3 states that additional claims in optionalClaims SHOULD be avoided unless there is a compelling reason, as they may harm interoperability.