This guide covers the full loop: activate → store → verify on startup → deactivate. It assumes you already have a workspace and a license key.
Dependencies: reqwest (blocking or async), serde_json, ed25519-dalek, base64 and hex-literal.
1. Activate
src/license.rs
use serde_json::json;
const BASE: &str = "https://keygate.unionuser.com";
pub fn activate(license_key: &str, device_id: &str) -> Result<String, Box<dyn std::error::Error>> {
let client = reqwest::blocking::Client::new();
let res = client
.post(format!("{}/api/v1/license/activate", BASE))
.json(&json!({
"license_key": license_key,
"identifier": device_id,
"identifier_type": "device"
}))
.send()?;
let body: serde_json::Value = res.json()?;
if body["success"] != true {
return Err(body["error"]["code"].as_str().unwrap_or("UNKNOWN").into());
}
Ok(body["data"]["token"].as_str().unwrap_or_default().to_string())
}
2. Verify offline
src/verify.rs
use base64::{engine::general_purpose::URL_SAFE_NO_PAD, Engine};
use ed25519_dalek::{Signature, VerifyingKey};
use serde_json::Value;
const RAW_PUBLIC: [u8; 32] = hex_literal::hex!("bf17435ee7b937b3592808941683c21d37c4e124d95d4e8fdd86fe775dd23b11");
pub fn verify_token(token: &str, device_id: &str) -> Result<Value, Box<dyn std::error::Error>> {
let (payload_b64, sig_b64) = token.split_once('.').ok_or("BAD_TOKEN")?;
let sig_bytes = URL_SAFE_NO_PAD.decode(sig_b64)?;
let signature = Signature::from_slice(&sig_bytes)?;
let key = VerifyingKey::from_bytes(&RAW_PUBLIC)?;
key.verify_strict(payload_b64.as_bytes(), &signature)?;
let claims: Value = serde_json::from_slice(&URL_SAFE_NO_PAD.decode(payload_b64)?)?;
if claims["did"] != device_id {
return Err("DEVICE_MISMATCH".into());
}
Ok(claims)
}
3. Deactivate
src/license.rs
pub fn deactivate(license_key: &str, device_id: &str) -> Result<(), Box<dyn std::error::Error>> {
reqwest::blocking::Client::new()
.post(format!("{}/api/v1/license/deactivate", BASE))
.json(&json!({ "license_key": license_key, "identifier": device_id }))
.send()?;
Ok(())
}
Tauri notes
- Keep licensing in Rust commands; expose only capability flags to the frontend.
- Store the token in app_data_dir, not the frontend localStorage.
- Prefer ed25519-dalek’s verify_strict to reject weak keys.