SD-JWT / Compact · JWS JSON

Share selected claims with verifiable presentations

Issue, selectively present, and verify RFC 9901 SD-JWTs in Ruby. Use ruby-jwt and OpenSSL for signatures, with recursive disclosures and holder key binding handled by the gem.

Quick startRuby
require "sd_jwt"

issuer_key = OpenSSL::PKey::EC.generate("prime256v1")
holder_key = OpenSSL::PKey::EC.generate("prime256v1")
holder_jwk = JWT::JWK.new(holder_key).export.transform_keys(&:to_s)

issuer = SDJWT::Issuer.new(signing_key: issuer_key, alg: "ES256")
credential = issuer.issue(
  { "iss" => "https://issuer.example", "exp" => Time.now.to_i + 3600,
    "name" => "Example", "address" => { "street" => "Harbor Street", "city" => "Port" } },
  disclose: ["/name", "/address", "/address/street"],
  decoys: 2,
  holder_jwk: holder_jwk,
  header: { "typ" => "example+sd-jwt", "kid" => "key-1" }
)

held = SDJWT.parse(credential.to_s) # Unauthenticated holder-side parsing.
presentation = held.present(
  only: ["/name"],
  key_binding: { key: holder_key, alg: "ES256", aud: "https://verifier.example", nonce: "transaction-nonce" }
)

verifier = SDJWT::Verifier.new(
  algorithms: ["ES256"],
  issuer_key: issuer_key, # Or ->(untrusted_header, untrusted_payload) { trusted_key_lookup(...) }
  issuer: "https://issuer.example",
  required_claims: ["iss", "exp", "cnf"],
  require_key_binding: true,
  audience: "https://verifier.example",
  nonce: "transaction-nonce",
  max_kb_age: 300
)
result = verifier.verify(presentation)
result.claims                    # Immutable, authenticated disclosed claims.
result.key_binding_verified      # true

Installation

Add the gem to your Gemfile:

gem "sd_jwt"

Run bundle install, then try the quick start. Requires Ruby 3.3 or later.

For supported dependencies and optional integrations, see the installation guide.

Scope & documentation

Applications must establish issuer trust and manage nonce replay protection, revocation, and credential profile rules. Parsing alone does not authenticate a credential. EdDSA, symmetric holder keys, and SD-CWT are outside scope.

Read the full documentation for supported formats, examples, and API details.

No independent external human security audit has been completed. Automated tests and RFC conformance checks do not replace such an audit. Security policy.