Alpha Software: This library is under active development. APIs may change. Test thoroughly before production use.
Multi-language SDKs for encoding and decoding MOSIP Claim 169 QR codes — a compact, secure format for digital identity credentials.
Try it now: Interactive Playground — encode and decode QR codes in your browser
Claim 169 QR codes enable offline verification of identity credentials — no internet connection required at the point of verification. Common use cases include:
- Border control & immigration — verify travel documents without network access
- Healthcare credentials — vaccination records, insurance cards, patient IDs
- Government benefits — social protection programs, subsidy distribution
- Digital driver's licenses — offline-verifiable mobile driving permits
- Event access — tamper-evident tickets with identity binding
The format is designed for constrained environments: a typical credential fits in a single QR code scannable by any smartphone camera.
MOSIP Claim 169 is an IANA-registered specification for encoding identity data in QR codes. This project provides SDKs for multiple languages:
| SDK | Package | Use Case |
|---|---|---|
| Rust | claim169-core |
High-performance core library, embedded systems |
| Python | claim169 |
Server-side integration, HSM support |
| TypeScript/JavaScript | claim169 |
Browser apps, Node.js services |
| Kotlin/Java | claim169-core |
Android apps, JVM server-side |
All SDKs share the same Rust core via native bindings (Python, Kotlin/Java) or WebAssembly (TypeScript), ensuring consistent behavior across platforms.
- Encode and decode identity credentials to/from QR codes
- Sign and verify with Ed25519 or ECDSA P-256
- Encrypt and decrypt with AES-GCM (128 or 256 bit)
- Pluggable crypto backends for HSM, cloud KMS, smart cards, and TPM integration
- Comprehensive security including weak key rejection, decompression limits, and timestamp validation
Identity Data → CBOR → CWT → COSE_Sign1 → [COSE_Encrypt0] → zlib → Base45 → QR Code
| Operation | Algorithms |
|---|---|
| Signing | Ed25519, ECDSA P-256 (ES256) |
| Encryption | AES-128-GCM, AES-256-GCM |
| Compression | zlib (DEFLATE) |
| Encoding | Base45 |
claim-169/
├── core/
│ ├── claim169-core/ # Rust core library
│ ├── claim169-jni/ # Kotlin/Java bindings (UniFFI)
│ ├── claim169-wasm/ # WebAssembly bindings
│ └── claim169-python/ # Python bindings (PyO3)
├── sdks/
│ ├── kotlin/ # Kotlin/Java SDK
│ └── typescript/ # TypeScript/JavaScript SDK
├── playground/ # Interactive web playground
├── examples/ # Runnable examples (Python, TypeScript)
├── fuzz/ # Fuzz testing targets
├── test-vectors/ # Test vectors for compliance
└── tools/ # CLI and utilities
[dependencies]
claim169-core = "0.2.0-alpha"use claim169_core::{Decoder, Encoder, Claim169, CwtMeta};
// Decode and verify a QR code
let result = Decoder::new(qr_content)
.verify_with_ed25519(&public_key)?
.decode()?;
println!("Name: {:?}", result.claim169.full_name);Encoding example
// Create and sign a new credential
let claim = Claim169::default()
.with_id("123456789")
.with_full_name("Jane Doe");
let meta = CwtMeta::new()
.with_issuer("https://issuer.example.com")
.with_expires_at(1800000000);
let qr_data = Encoder::new(claim, meta)
.sign_with_ed25519(&private_key)?
.encode()?;pip install claim169from claim169 import decode_with_ed25519
# Decode and verify a QR code
result = decode_with_ed25519(qr_text, public_key_bytes)
print(f"Name: {result.claim169.full_name}")
print(f"Expired: {result.cwt_meta.is_expired()}")Encoding example
from claim169 import Claim169Input, CwtMetaInput, encode_with_ed25519
claim = Claim169Input(id="123", full_name="Jane Doe")
meta = CwtMetaInput(issuer="https://issuer.example.com")
qr_data = encode_with_ed25519(claim, meta, private_key_bytes)npm install claim169import { Decoder } from 'claim169';
// Decode and verify a QR code
const result = new Decoder(qrText)
.verifyWithEd25519(publicKey)
.decode();
console.log(`Name: ${result.claim169.fullName}`);Encoding example
import { Encoder, Claim169Input, CwtMetaInput } from 'claim169';
const claim: Claim169Input = { id: "123", fullName: "Jane Doe" };
const meta: CwtMetaInput = { issuer: "https://issuer.example.com" };
const qrData = new Encoder(claim, meta)
.signWithEd25519(privateKey)
.encode();// Gradle (Kotlin DSL)
implementation("org.idpass.claim169:claim169-core:0.1.0-alpha.3")import org.idpass.claim169.*
// Decode and verify a QR code
val result = Claim169.decode(qrText) {
verifyWithEd25519(publicKey)
}
println("Name: ${result.claim169.fullName}")Encoding example
val qrData = Claim169.encode(
claim169 {
id = "123456789"
fullName = "Jane Doe"
},
cwtMeta {
issuer = "https://issuer.example.com"
expiresAt = 1800000000L
}
) {
signWithEd25519(privateKey)
}- Rust 1.75+ with cargo
- Python 3.8+ with maturin (for Python bindings)
- Node.js 18+ with npm (for TypeScript SDK)
- JDK 17+ with Gradle (for Kotlin SDK)
- wasm-pack (for WebAssembly bindings)
| Platform | Minimum Version | Notes |
|---|---|---|
| Rust | 1.75+ | MSRV tested in CI |
| Python | 3.8+ | Wheels for Linux, macOS, Windows |
| Node.js | 18+ | ESM and CommonJS |
| Browsers | Chrome 89+, Firefox 89+, Safari 15+ | Via WebAssembly |
| JVM | JDK 17+ | Kotlin/Java via JNA |
| Android | API 24+ (7.0) | Native .so via JNA |
# Clone the repository
git clone https://github.com/idpass/claim-169.git
cd claim-169
# Build Rust libraries
cargo build --release
# Run tests
cargo test --all-features
# Build Python bindings
cd core/claim169-python
maturin develop --release
# Build WASM and TypeScript SDK
cd ../../sdks/typescript
npm install
npm run build# Core library only
cargo build -p claim169-core --release
# WASM bindings
cd core/claim169-wasm
wasm-pack build --target bundler --release
# Python bindings
cd core/claim169-python
maturin build --release
# Kotlin/Java SDK (requires native library)
cargo build -p claim169-jni
cd sdks/kotlin
./gradlew :claim169-core:testThis library implements several security measures:
- Signature verification with Ed25519 and ECDSA P-256
- Weak key rejection (all-zeros keys, small-order Ed25519 points)
- Decompression limits to prevent zip bomb attacks (default: 64KB)
- CBOR depth limits to prevent stack overflow (max: 128)
- Timestamp validation with configurable clock skew tolerance
- Memory zeroization for sensitive key material
See SECURITY.md for detailed security information and threat model.
Please report security vulnerabilities through GitHub's private vulnerability reporting. Do not use public GitHub issues for security reports.
- Rust API Documentation
- MOSIP Claim 169 Specification
- Examples - Runnable Python and TypeScript examples
- Contributing Guide
- Security Policy
- Changelog
# Run all tests
cargo test --all-features
# Run with verbose output
cargo test --all-features -- --nocapture
# Run fuzz tests (requires nightly)
cd fuzz
cargo +nightly fuzz run fuzz_decodeContributions are welcome! See CONTRIBUTING.md for detailed guidelines.
Quick overview:
- Fork the repository and create a feature branch
- Make your changes following the project's code style
- Ensure all tests pass (
cargo test --all-features) - Submit a Pull Request
Please ensure code is formatted (cargo fmt) and has no clippy warnings (cargo clippy --all-features).
This project is licensed under the MIT License - see the LICENSE file for details.
- MOSIP for the Claim 169 specification
- RustCrypto for cryptographic primitives
- coset for COSE implementation