| Crates.io | gatewarden |
| lib.rs | gatewarden |
| version | 0.1.2 |
| created_at | 2025-12-18 07:19:46.424953+00 |
| updated_at | 2025-12-18 07:36:26.287132+00 |
| description | Hardened Keygen.sh license validation infrastructure |
| homepage | https://github.com/Michael-A-Kuykendall/gatewarden |
| repository | https://github.com/Michael-A-Kuykendall/gatewarden |
| max_upload_size | |
| id | 1991884 |
| size | 1,959,505 |
Yes, the logo is a bit much for a license validation library. We're aware.
Gatewarden is for developers who use Keygen.sh and want cryptographic assurance—not just HTTP success—that a license validation response is authentic.
Hardened means Gatewarden treats license validation as an adversarial protocol, not a trusted API call. It upgrades Keygen's client-side validation from "API trust" to "cryptographic trust."
Most Keygen integrations just check meta.valid == true in the JSON response. That's fine until someone points your app at a proxy that returns {"meta":{"valid":true}} for every request.
Gatewarden verifies the Ed25519 signature that Keygen attaches to every response, ensuring:
| Threat | Protection |
|---|---|
| MITM / proxy spoofing | Response must be signed by Keygen's private key |
| Replay attacks | Response rejected if older than 5 minutes |
| Body tampering | SHA-256 digest verified (when present) |
| Cache tampering | Cached records re-verified on load |
| Missing signatures | Fail-closed: no signature = rejected |
Gatewarden does not attempt to:
If an attacker has full control of the machine, they can bypass any client-side check. Gatewarden raises the bar from "intercept HTTP" to "reverse engineer binary."
use gatewarden::{GatewardenConfig, LicenseManager};
use std::time::Duration;
fn main() -> Result<(), gatewarden::GatewardenError> {
let config = GatewardenConfig {
app_name: "myapp",
feature_name: "pro",
account_id: "your-keygen-account-id",
public_key_hex: "your-keygen-ed25519-verify-key",
required_entitlements: &["PRO_FEATURE"],
user_agent_product: "myapp",
cache_namespace: "myapp",
offline_grace: Duration::from_secs(24 * 60 * 60), // 24 hours
};
let manager = LicenseManager::new(config)?;
// validate_key: always hits Keygen, verifies signature, updates cache
let result = manager.validate_key("LICENSE-KEY")?;
if result.valid {
println!("License valid (cached: {})", result.from_cache);
}
Ok(())
}
| Method | Behavior |
|---|---|
validate_key(key) |
Online validation → signature verify → cache |
check_access(key) |
Prefer cache (if within offline grace) → fallback to online |
Both methods verify signatures and entitlements. Use validate_key when you want fresh validation; use check_access for typical runtime checks where offline grace is acceptable.
Gatewarden uses typed errors for precise handling:
use gatewarden::GatewardenError;
match manager.validate_key(&license_key) {
Ok(result) if result.valid => { /* proceed */ }
Ok(_) => { /* license invalid */ }
// License issues (user-actionable)
Err(GatewardenError::InvalidLicense) => { /* expired or revoked */ }
Err(GatewardenError::EntitlementMissing { code }) => { /* wrong tier */ }
// Security events (log and investigate)
Err(GatewardenError::SignatureInvalid) => { /* possible tampering */ }
Err(GatewardenError::SignatureMissing) => { /* response unsigned */ }
Err(GatewardenError::DigestMismatch) => { /* body modified */ }
Err(GatewardenError::ResponseTooOld { .. }) => { /* replay attempt */ }
// Network issues (may use offline cache)
Err(GatewardenError::KeygenTransport(_)) => { /* try check_access() */ }
Err(e) => { /* other errors */ }
}
| Field | Description |
|---|---|
account_id |
Your Keygen account UUID |
public_key_hex |
Keygen's Ed25519 verify key (64 hex characters) |
required_entitlements |
Entitlement codes the license must have |
offline_grace |
How long cached validations remain valid when offline |
cache_namespace |
Directory name for cache files (under user cache dir) |
Get your public key from Keygen Dashboard → Settings → Public Key.
When online validation fails due to network issues, Gatewarden falls back to the authenticated cache:
offline_grace durationMost license libraries fail open. Gatewarden fails closed:
Security failures are distinguishable from network failures through typed errors, so you can handle them appropriately.
What Gatewarden protects:
Philosophy: Licensing is not a business rule—it is an adversarial interface. Gatewarden treats it accordingly.
See examples/basic_validation.rs for a complete working example with error handling.
See LOCAL_TESTING.md for integration testing against real Keygen APIs.
See CONTRIBUTING.md.
MIT — see LICENSE.