JET (JSON Encrypted Token) is a modern cryptographic token format, designed as a secure alternative to JWT and JWE. Unlike JWT, which often encodes sensitive data without encryption, JET is encrypted by design โ using strong authenticated symmetric ciphers and memoryโhard key derivation functions.
Modern token security faces critical challenges with existing standards:
JWT's fundamental flaws:
- โ Zero confidentiality โ payloads are Base64-encoded, readable by anyone with basic tools
- โ Algorithm vulnerabilities โ
"alg": "none"attacks and HMAC/RSA confusion exploits - โ No replay protection โ stolen tokens remain valid until natural expiration
- โ Sensitive data exposure โ user details, roles, and permissions visible in logs and traffic
JWE's complexity burden:
- โ Key distribution nightmare โ complex infrastructure for key sharing and rotation
- โ Multiple algorithm coordination โ increased attack surface and implementation errors
- โ Development overhead โ steep learning curve and error-prone integration
JET solves these with modern cryptographic design:
- โ Industry-standard encryption by default โ AES-256-GCM and ChaCha20-Poly1305 protect all payload data
- โ Password-based simplicity โ no complex key infrastructure, just strong password management
- โ
Extensible crypto suite โ header-declared
encandkdfalgorithms, ready for future standards - โ Memory-hard key derivation โ currently supports Argon2id and Scrypt with configurable parameters
- โ Per-token key isolation โ unique salts generate independent encryption keys for each token
- โ Built-in replay defense โ token IDs and strict timing validation prevent reuse attacks
- โ Authenticated headers โ tamper-proof metadata without exposing sensitive information
- โ Future-proof design โ algorithm agility allows seamless upgrades to emerging cryptographic standards
- โ Single responsibility โ focused on encryption, avoiding JWT's multi-purpose confusion
Bottom line: JET delivers enterprise-grade security with developer-friendly simplicity โ encrypted by design, not as an afterthought.
| Feature | JWT | JWE | JET |
|---|---|---|---|
| Payload Encryption | โ Base64 only | โ Yes | โ Yes |
| Implementation Complexity | โ Simple | โ Complex | โ Simple |
| Key Management | โ Simple | โ Complex PKI | โ Password-based |
| Memory-Hard KDF | โ No | โ No | โ Argon2id/Scrypt |
| Per-Token Unique Keys | โ No | โ No | โ Yes |
| Built-in Replay Protection | โ No | โ No | โ Token ID + timing |
| Algorithm Agility | โ Header-declared | ||
| Quantum Resistance | โ RSA vulnerable | โ Current standards | |
| Development Learning Curve | โ Low | โ High | โ Low |
- AESโ256โGCM โ industry standard, hardware accelerated on most modern processors
- ChaCha20โPoly1305 โ high performance on platforms without dedicated AES hardware
- XChaCha20โPoly1305 โ ChaCha20 with 192-bit nonces instead of 96-bit, reducing collision risk
- Argon2id โ Password Hashing Competition winner, optimal resistance to GPU/ASIC attacks
- Scrypt โ established memoryโhard KDF with proven security properties
A JET token is two Base64Url parts separated by .:
<header_base64url>.<payload_base64url>
Contains algorithm parameters, KDF configuration, and public metadata:
{
"enc": "AES-256-GCM",
"kdf": {
"t": "Argon2id",
"m": 65536,
"i": 3,
"p": 1,
"s": "j6K93DzEKt5dTYbA8lF2gw"
},
"md": {
"app": "my-application"
},
"jti": "019b2df2-9778-743c-8d68-941b72a5f08b",
"iat": 1766002431,
"nbf": 1766002431,
"exp": 1766006031,
"typ": "JET"
}Contains two AEAD outputs: the encrypted content and the encrypted CEK (Content Encryption Key):
{
"ct": {
"c": "U4D3Dwydw5pBimccuMBVentQcECqiV2YLxyLaPxnqkJw5D4Ex9EflxhUvheqg0V-zBYlGxJ1MBSWQIsV05T6K00dnJKDgK2rBbVPxTBfR5WcAMQPpFot6Eolm2EJHOd4lFPsr-JoZu9Xag7xOBfKHmYIL766BBAwUUGQmPf6bR9B8qVip6QZCAdqtPjppRmAl-QgvigzjlUNL24Cz1fVwO4Mww",
"n": "CFHk6NqPPOaYmTcz"
},
"k": {
"c": "8sKBYXTtbTFD3SKqzIEIByyWOr9mUtBTHqRMW3h-qtnsBOPuYj6IKavo757DPh2_",
"n": "KgKh0LRev7b5Cf9v"
}
}- Header JSON serves as Additional Authenticated Data (AAD) for both CEK and content encryption
- Salt is publicly stored in header and used for password-based key derivation
- Modifying any header field invalidates the token through authentication failure
Encode Process:
- Serialize sensitive payload to JSON bytes
- Generate cryptographically random salt and derive KEK (Key Encryption Key) using chosen KDF
- Generate random CEK (Content Encryption Key) and unique nonces for both operations
- Build canonical header JSON for use as authenticated additional data
- Encrypt CEK with derived KEK, producing CEK ciphertext and authentication tag
- Encrypt payload with CEK, producing content ciphertext and authentication tag
- Construct final payload JSON with both encrypted components, encode header and payload as Base64Url
Decode Process:
- Parse token structure and Base64Url-decode header and payload components
- Reconstruct header JSON exactly as used during encoding for AAD consistency
- Extract KDF parameters and derive KEK from password and salt
- Decrypt CEK using derived KEK, nonce, and authentication tag with header as AAD
- Decrypt content using recovered CEK, nonce, and authentication tag with header as AAD
- Parse decrypted JSON to recover original sensitive data
Implementation Note: The reference uses exact decoded header JSON as AAD to ensure byte-perfect consistency between encoding and decoding operations.
JET implements multiple layers of replay protection:
Token Identifier (jti): Each token contains a unique GUID Version 7 identifier in the header
Temporal Controls: Built-in timestamp validation with iat, nbf, and exp claims
Application Integration: Validation hooks allow server-side token ID tracking and revocation
Security Model: While AEAD nonces ensure semantic security (identical payloads produce different ciphertexts), replay protection requires application-level validation of token identifiers and temporal bounds.
Best Practice: Implement short-lived token ID cache to detect and reject replayed tokens within their validity window.
using JetNet;
using JetNet.Crypto;
using SysCrypto = System.Security.Cryptography;
// Secure password handling
Span<byte> _key = stackalloc byte[32];
SysCrypto.RandomNumberGenerator.Fill(_key);
using var jet = new Jet(_key);
SysCrypto.CryptographicOperations.ZeroMemory(_key);
// Sensitive payload data
var _payload = new
{
user = "Soheil Jashnsaz",
role = "admin",
claims = new
{
iss = "mycompany.com",
sub = "user-authentication",
aud = new string[] { "app-web", "app-mobile", "api-service" }
}
};
// Public metadata (will be in authenticated but unencrypted header)
Dictionary<string, string> _metadata = new Dictionary<string, string>()
{
{ "app", "my-application" }
};
// Strong key derivation configuration
var _kdf = KdfFactory.CreateArgon2id(parallelism: 1, memory: 65536, iterations: 3);
// Create encrypted token
string _token = jet.Encode(_payload, _kdf, metadata: _metadata);
// Decode with validation
var _decoded = jet.Decode<dynamic>(_token, ValidateMetadata, ValidateTokenID);
Console.WriteLine("Token created successfully");
Console.WriteLine($"User: {_decoded.user}");
Console.WriteLine($"Role: {_decoded.role}");
// Validation functions
bool ValidateMetadata(Dictionary<string, string> metadata)
{
return metadata.ContainsKey("app") && metadata["app"] == "my-application";
}
bool ValidateTokenID(string id)
{
// Implement server-side revocation checking
return !IsTokenRevoked(id);
}
bool IsTokenRevoked(string tokenId)
{
// TODO: Implement with your persistence layer (Redis/Database)
// For production, check revocation list from your data store
return false;
}Comprehensive round-trip validation across supported cipher/KDF combinations:
- Argon2id + AESโ256โGCM
- Argon2id + ChaCha20โPoly1305
- Argon2id + XChaCha20โPoly1305
- Scrypt + AESโ256โGCM
- Scrypt + ChaCha20โPoly1305
- Scrypt + XChaCha20โPoly1305
Encoded Token:
eyJlbmMiOiJBRVMtMjU2LUdDTSIsImV4cCI6MTc2NjAwNjAzMSwiaWF0IjoxNzY2MDAyNDMxLCJqdGkiOiIwMTliMmRmMi05Nzc4LTc0M2MtOGQ2OC05NDFiNzJhNWYwOGIiLCJrZGYiOnsidCI6IkFyZ29uMmlkIiwibSI6NjU1MzYsImkiOjMsInAiOjEsInMiOiJqNks5M0R6RUt0NWRUWWJBOGxGMmd3In0sIm1kIjp7ImFwcCI6Im15LWFwcGxpY2F0aW9uIn0sIm5iZiI6MTc2NjAwMjQzMSwidHlwIjoiSkVUIn0.eyJjdCI6eyJjIjoiVTREM0R3eWR3NXBCaW1jY3VNQlZlbnRRY0VDcWlWMllMeHlMYVB4bnFrSnc1RDRFeDlFZmx4aFV2aGVxZzBWLXpCWWxHeEoxTUJTV1FJc1YwNVQ2SzAwZG5KS0RnSzJyQmJWUHhUQmZSNVdjQU1RUHBGb3Q2RW9sbTJFSkhPZDRsRlBzci1Kb1p1OVhhZzd4T0JmS0htWUlMNzY2QkJBd1VVR1FtUGY2YlI5QjhxVmlwNlFaQ0FkcXRQanBwUm1BbC1RZ3ZpZ3pqbFVOTDI0Q3oxZlZ3TzRNd3ciLCJuIjoiQ0ZIazZOcVBQT2FZbVRjeiJ9LCJrIjp7ImMiOiI4c0tCWVhUdGJURkQzU0txeklFSUJ5eVdPcjltVXRCVEhxUk1XM2gtcXRuc0JPUHVZajZJS2F2bzc1N0RQaDJfIiwibiI6IktnS2gwTFJldjdiNUNmOXYifX0
After Decryption (sensitive data protected):
{
"user": "Soheil Jashnsaz",
"role": "admin",
"claims": {
"iss": "mycompany.com",
"sub": "user-authentication",
"aud": [
"app-web",
"app-mobile",
"api-service"
]
}
}
JET supports two input modes for authentication: byte-based master keys and string-based passwords.
While both are secure, byte arrays are strongly recommended for high-security applications, as they allow full control over memory lifecycle and zeroization.
The most secure way to initialize JET is by providing a raw byte sequence.
This approach avoids managed strings, prevents GC exposure, and enables direct integration with HSMs or key vaults.
Example (secure memory use):
Span<byte> key = stackalloc byte[32];
RandomNumberGenerator.Fill(key);
using var jet = new Jet(key);
CryptographicOperations.ZeroMemory(key);Advantages:
- ๐ง Never exposes secrets in managed memory
- โก Enables direct use of hardware or derived session keys
- ๐งฉ Compatible with secure key lifecycle management
- ๐งน Can be safely wiped using
CryptographicOperations.ZeroMemory
For convenience, JET also accepts traditional passwords as UTF-8 strings.
Internally, the string is converted to bytes, used to derive the encryption key, and then immediately wiped from memory.
Example:
using var jet = new Jet("CorrectHorseBatteryStaple9X2m");Essential Requirements:
- โ Minimum 16 characters with high entropy
- โ Cryptographically random generation preferred
- โ Mixed character classes (uppercase, lowercase, digits, symbols)
- โ Avoid dictionary words, patterns, or personal information
- โ Unique passwords per application/service
- โ Secure storage using password managers
Example High-Entropy Password:
G7$wR9!vZp2#qK8d
Passphrase Alternative:
Multiple unrelated words can provide equivalent security with better memorability:
correct-horse-battery-staple-9X2m
| Mode | Type | Security | Use Case |
|---|---|---|---|
| Master Key (Byte Array) | ReadOnlySpan<byte> |
๐ Highest | Cryptographic systems, secure sessions, HSM integration |
| Password (String) | string |
๐ก Moderate | User-entered credentials, UI-based applications |
JET welcomes community contributions including:
- Cryptographic analysis and security reviews
- Performance optimizations and benchmarks
- Additional language implementations
- Protocol extensions and algorithm proposals
MIT License
- Newtonsoft.Json (Json.NET is a popular high-performance JSON framework for .NET)
- NSec.Cryptography (A modern and easy-to-use cryptographic library for .NET based on libsodium)