pub struct ApiKey {
pub id: String,
pub user_id: String,
pub name: String,
pub prefix: String,
pub secret_hash: String,
pub scopes: Option<String>,
pub expires_at: Option<u64>,
pub last_used_at: Option<u64>,
pub created_at: u64,
}Expand description
One stored API key. The secret_hash is what’s persisted; the
plaintext secret is returned to the caller exactly once at create
time (see ApiKeyStore::create).
Fields§
§id: StringStable identifier — what the dashboard / management UI lists.
Format: key_<24-char-base64url>. Distinct from prefix so a
user can revoke by id without seeing the secret prefix.
user_id: StringUser who owns this key. Auth context resolves to this user_id when the key authenticates.
name: StringFriendly name set by the owner. Free-form; UI-only.
prefix: StringFirst 16 chars of the FULL plaintext token (pk.key_<8 id chars>).
Safe to display in management UIs since this prefix encodes
only the key id, not any of the secret material — the secret
starts AFTER the second . separator. Lets the user
distinguish keys by sight without ever exposing the secret.
secret_hash: StringHMAC-SHA256 hash of the secret using a server-side pepper
(PYLON_API_KEY_PEPPER, or a fixed dev pepper when unset).
Verified at request time via constant-time compare.
Why HMAC-SHA256, not Argon2? Argon2 exists to slow brute force of LOW-entropy passwords. API key secrets are 32 random bytes (256 bits) — brute force is computationally infeasible regardless of hash speed. Using Argon2 here would add ~50ms of latency per request for zero security benefit. SHA-256 HMAC at ~1µs gives the same effective security plus 50000× throughput.
scopes: Option<String>Comma-separated scope strings. Application-defined; pylon stores opaquely.
expires_at: Option<u64>Unix timestamp at which this key stops being valid. None for no-expiry keys.
last_used_at: Option<u64>Unix timestamp of the most recent successful auth — refreshed on every verify. None until the first use.
created_at: u64