SdJwt.Net
1.0.0
See the version list below for details.
dotnet add package SdJwt.Net --version 1.0.0
NuGet\Install-Package SdJwt.Net -Version 1.0.0
<PackageReference Include="SdJwt.Net" Version="1.0.0" />
<PackageVersion Include="SdJwt.Net" Version="1.0.0" />
<PackageReference Include="SdJwt.Net" />
paket add SdJwt.Net --version 1.0.0
#r "nuget: SdJwt.Net, 1.0.0"
#:package SdJwt.Net@1.0.0
#addin nuget:?package=SdJwt.Net&version=1.0.0
#tool nuget:?package=SdJwt.Net&version=1.0.0
SdJwt.Net Core - RFC 9901 Implementation
A production-ready .NET library for Selective Disclosure JSON Web Tokens (SD-JWTs) compliant with RFC 9901. This is the core library that provides fundamental SD-JWT functionality with enhanced security, performance optimization, and comprehensive multi-platform support.
Features
- RFC 9901 Compliant: Complete implementation of Selective Disclosure for JSON Web Tokens
- JWS JSON Serialization: Full support for Flattened and General JSON formats (RFC 9901 Section 8)
- Enhanced Security: Blocks weak algorithms (MD5, SHA-1), enforces approved SHA-2 family
- Multi-Platform: .NET 8, 9, and .NET Standard 2.1 with platform-specific optimizations
- Production Ready: Battle-tested with comprehensive tests and security hardening
Installation
dotnet add package SdJwt.Net
Quick Start
SD-JWT Structure
graph LR
subgraph SdJwtCompactFormat[SD-JWT Compact Format]
Header[Base64url Header: alg, typ]
Payload[Base64url Payload: iss, iat, exp, _sd hashes, _sd_alg sha-256]
Sig[Base64url Signature]
Disc1[~Disclosure 1: salt + claim_name + value]
Disc2[~Disclosure 2: salt + claim_name + value]
KB[~KB-JWT: nonce + aud + iat]
end
Header -.->|.| Payload
Payload -.->|.| Sig
Sig -.->|~| Disc1
Disc1 -.->|~| Disc2
Disc2 -.->|~| KB
style Header fill:#1b4332,color:#fff
style Payload fill:#2d6a4f,color:#fff
style Sig fill:#40916c,color:#fff
style KB fill:#d62828,color:#fff
Basic SD-JWT Creation
using SdJwt.Net.Issuer;
using Microsoft.IdentityModel.Tokens;
using System.Security.Cryptography;
// Create signing key
using var key = ECDsa.Create();
var signingKey = new ECDsaSecurityKey(key) { KeyId = "issuer-key-1" };
var holderJwk = JsonWebKeyConverter.ConvertFromSecurityKey(
new ECDsaSecurityKey(ECDsa.Create()) { KeyId = "holder-key-1" });
// Create SD-JWT issuer
var issuer = new SdIssuer(signingKey, SecurityAlgorithms.EcdsaSha256);
// Define claims with selective disclosure
var claims = new JwtPayload
{
["iss"] = "https://issuer.example.com",
["given_name"] = "John",
["family_name"] = "Doe",
["email"] = "john.doe@example.com",
["address"] = new {
street = "123 Main St",
city = "Anytown",
state = "CA"
}
};
// Configure selective disclosure
var options = new SdIssuanceOptions
{
DisclosureStructure = new
{
given_name = true,
family_name = true,
email = true,
address = new { city = true, state = true }
}
};
// Issue SD-JWT
var result = issuer.Issue(claims, options, holderJwk);
Holder Creates Presentation
using SdJwt.Net.Holder;
using Microsoft.IdentityModel.Tokens;
using System.IdentityModel.Tokens.Jwt;
using System.Security.Cryptography;
// Create holder from issuance
var holder = new SdJwtHolder(result.Issuance);
using var holderPrivateEcdsa = ECDsa.Create();
var holderPrivateKey = new ECDsaSecurityKey(holderPrivateEcdsa) { KeyId = "holder-key-1" };
var kbPayload = new JwtPayload
{
["aud"] = "https://verifier.example.com",
["nonce"] = "job-application-2024-12345",
["iat"] = DateTimeOffset.UtcNow.ToUnixTimeSeconds()
};
// Create selective presentation (only disclose email and city)
var presentation = holder.CreatePresentation(
disclosure => disclosure.ClaimName == "email" || disclosure.ClaimName == "city",
kbPayload, holderPrivateKey, SecurityAlgorithms.EcdsaSha256);
// For SD-JWT (without KB-JWT), compact output follows RFC 9901 and ends with "~".
// For SD-JWT+KB, the final component is the KB-JWT (no trailing empty component).
Verification
sequenceDiagram
participant Holder as Holder (Wallet)
participant Verifier as Verifier
Holder->>Verifier: VP Token (SD-JWT~email~KB-JWT)
Note over Verifier: Step 1 - Parse & split
Verifier->>Verifier: Split on ~ separator
Verifier->>Verifier: Decode header / payload / sig
Note over Verifier: Step 2 - Verify issuer signature
Verifier->>Verifier: Resolve issuer JWKS
Verifier->>Verifier: Validate JWT signature
Note over Verifier: Step 3 - Reconstruct disclosures
Verifier->>Verifier: For each disclosure: SHA-256(salt+name+value)
Verifier->>Verifier: Verify hash appears in _sd array
Note over Verifier: Step 4 - Verify Key Binding
Verifier->>Verifier: Verify KB-JWT signature with holder key
Verifier->>Verifier: Check nonce matches expected value
Verifier->>Verifier: Check aud matches verifier URL
Verifier-->>Holder: Verification Result + Revealed Claims
using SdJwt.Net.Verifier;
// Create verifier with key resolver
var verifier = new SdVerifier(async issuer =>
{
// Resolve issuer's public key from trusted source
return await ResolveIssuerKeyAsync(issuer);
});
// Verify presentation
var validationParams = new TokenValidationParameters
{
ValidateIssuer = true,
ValidIssuer = "https://issuer.example.com",
ValidateAudience = false,
ValidateLifetime = true
};
var kbParams = new TokenValidationParameters
{
ValidateAudience = true,
ValidAudience = "https://verifier.example.com",
ValidateLifetime = true
};
// Verify presentation with expected nonce for replay protection
var expectedNonce = "job-application-2024-12345";
var result = await verifier.VerifyAsync(presentation, validationParams, kbParams, expectedNonce);
if (result.KeyBindingVerified)
{
Console.WriteLine($"Key Binding Verified. Nonce: {result.KeyBindingJwtPayload?["nonce"]}");
}
// Optional strict policy controls (strict mode is enabled by default)
var verifierOptions = new SdVerifierOptions
{
StrictMode = true,
KeyBinding = new KeyBindingValidationPolicy
{
RequireKeyBinding = true,
ExpectedAudience = "https://verifier.example.com",
MaxKeyBindingJwtAge = TimeSpan.FromMinutes(5)
}
};
Security Features
- Algorithm Enforcement: Blocks MD5, SHA-1; enforces SHA-2 family
- Constant-time Operations: Protection against timing attacks
- Input Validation: Comprehensive validation throughout APIs
- Cross-platform Security: Consistent guarantees across platforms
Documentation
For comprehensive examples and advanced usage, see the main repository.
License
Licensed under the Apache License 2.0.
| Product | Versions Compatible and additional computed target framework versions. |
|---|---|
| .NET | net5.0 was computed. net5.0-windows was computed. net6.0 was computed. net6.0-android was computed. net6.0-ios was computed. net6.0-maccatalyst was computed. net6.0-macos was computed. net6.0-tvos was computed. net6.0-windows was computed. net7.0 was computed. net7.0-android was computed. net7.0-ios was computed. net7.0-maccatalyst was computed. net7.0-macos was computed. net7.0-tvos was computed. net7.0-windows was computed. net8.0 is compatible. net8.0-android was computed. net8.0-browser was computed. net8.0-ios was computed. net8.0-maccatalyst was computed. net8.0-macos was computed. net8.0-tvos was computed. net8.0-windows was computed. net9.0 is compatible. net9.0-android was computed. net9.0-browser was computed. net9.0-ios was computed. net9.0-maccatalyst was computed. net9.0-macos was computed. net9.0-tvos was computed. net9.0-windows was computed. net10.0 is compatible. net10.0-android was computed. net10.0-browser was computed. net10.0-ios was computed. net10.0-maccatalyst was computed. net10.0-macos was computed. net10.0-tvos was computed. net10.0-windows was computed. |
| .NET Core | netcoreapp3.0 was computed. netcoreapp3.1 was computed. |
| .NET Standard | netstandard2.1 is compatible. |
| MonoAndroid | monoandroid was computed. |
| MonoMac | monomac was computed. |
| MonoTouch | monotouch was computed. |
| Tizen | tizen60 was computed. |
| Xamarin.iOS | xamarinios was computed. |
| Xamarin.Mac | xamarinmac was computed. |
| Xamarin.TVOS | xamarintvos was computed. |
| Xamarin.WatchOS | xamarinwatchos was computed. |
-
.NETStandard 2.1
- Microsoft.Extensions.Logging.Abstractions (>= 9.0.6)
- System.IdentityModel.Tokens.Jwt (>= 8.12.1)
-
net10.0
- Microsoft.Extensions.Logging.Abstractions (>= 9.0.6)
- System.IdentityModel.Tokens.Jwt (>= 8.12.1)
-
net8.0
- Microsoft.Extensions.Logging.Abstractions (>= 9.0.6)
- System.IdentityModel.Tokens.Jwt (>= 8.12.1)
-
net9.0
- Microsoft.Extensions.Logging.Abstractions (>= 9.0.6)
- System.IdentityModel.Tokens.Jwt (>= 8.12.1)
NuGet packages (11)
Showing the top 5 NuGet packages that depend on SdJwt.Net:
| Package | Downloads |
|---|---|
|
SdJwt.Net.StatusList
SD-JWT Status List implementation for .NET, compliant with draft-ietf-oauth-status-list-13. Provides credential lifecycle management including revocation, suspension, and status verification for SD-JWT VCs. Ready for .NET 10. |
|
|
SdJwt.Net.Vc
SD-JWT Verifiable Credentials implementation for .NET, compliant with draft-ietf-oauth-sd-jwt-vc-15. Extends SdJwt.Net with comprehensive VC functionality including validation, type safety, and digital credential support. Ready for .NET 10. |
|
|
SdJwt.Net.Oid4Vci
A .NET library for OpenID for Verifiable Credential Issuance (OID4VCI) 1.0 protocol implementation. Provides transport-agnostic data models and utilities for SD-JWT integration with comprehensive flow support. Ready for .NET 10. |
|
|
SdJwt.Net.OidFederation
A .NET library for OpenID Federation 1.0 specification implementation. Provides trust chain validation, entity configuration management, and federation metadata support for SD-JWT ecosystems. Ready for .NET 10. |
|
|
SdJwt.Net.Oid4Vp
A .NET library for OpenID for Verifiable Presentations (OID4VP) 1.0 protocol implementation. Provides transport-agnostic data models and utilities for verifying SD-JWT presentations with Presentation Exchange v2.0.0 support. Ready for .NET 10. |
GitHub repositories
This package is not used by any popular GitHub repositories.
Version 1.0.0: RFC 9901 compliant SD-JWT implementation with
JWS JSON Serialization, enhanced security features, algorithm validation,
and multi-platform support. Ready for .NET 10.