FIDO2
The fido2 provider uses the FIDO2 hmac-secret extension to derive an AES-256-GCM encryption key from a hardware security key. Secrets are encrypted symmetrically — decryption requires the same physical FIDO2 key.
When to use it
The fido2 provider ties encryption to a physical hardware device using the CTAP2 hmac-secret extension. Use a security key and firmware that support the hmac-secret extension; FIDO2 support alone is not sufficient.
The config is fully portable: move your fnox.toml to any machine, plug in the same FIDO2 key, and it works.
Setup
fnox provider add secure fido2During setup, fnox will:
- Create a FIDO2 credential with the hmac-secret extension enabled
- Prompt for a PIN if required by the authenticator
- Generate a random salt for key derivation
- Verify the key works with a test assertion
- Store the credential ID, salt, and relying party ID in
fnox.toml
Configuration
[providers.secure]
type = "fido2"
credential_id = "a1b2c3..." # auto-generated hex credential ID
salt = "d4e5f6..." # auto-generated hex salt
rp_id = "fnox.secure" # relying party ID
# pin = "1234" # optional; if omitted, fnox prompts for the PIN when a TTY is availableUsage
Both encrypting and decrypting require the FIDO2 key:
# Encrypt (requires key touch)
fnox set MY_SECRET "supersecret" --provider secure
# Decrypt (requires key touch)
fnox get MY_SECRETWithin a single fnox exec invocation, the key is only touched once. The hmac-secret response is cached in memory for the duration of the process.
With credential leases
The fido2 provider works well with credential leases and the env = false secret option:
[providers.secure]
type = "fido2"
credential_id = "a1b2c3..."
salt = "d4e5f6..."
rp_id = "fnox.secure"
[secrets]
AWS_ACCESS_KEY_ID = { provider = "secure", env = false }
AWS_SECRET_ACCESS_KEY = { provider = "secure", env = false }
[leases.aws]
type = "aws-sts"
role_arn = "arn:aws:iam::123456789012:role/dev-role"
region = "us-east-1"How it works
- Setup: A FIDO2 credential is created with hmac-secret extension; credential ID and a random 32-byte salt are stored in config
- hmac-secret: The salt is sent to the authenticator during assertion, which returns a 32-byte HMAC derived from an internal device secret
- Key derivation: HKDF-SHA256 derives a 256-bit AES key from the HMAC response
- Encryption: AES-256-GCM encrypts the secret; output is
base64(nonce || ciphertext || tag)
The HMAC response is never stored on disk. It exists only in process memory after a key touch.
Important notes
Renaming providers invalidates cached credentials
The provider name is used in key derivation (HKDF context). Renaming a provider (e.g., from secure to my_fido2) will change the derived encryption key, making all previously encrypted secrets and cached lease credentials undecryptable. To migrate, keep the old provider available, create a new provider under the new name, and read values through the old provider before storing them with the new one. Verify the new values before removing the old configuration. Renaming first prevents decryption.
Requirements
- A FIDO2-compatible security key with hmac-secret extension support
- Confirm hmac-secret support for your device and firmware before setup
- PIN may be required depending on your key's configuration
FIDO2 vs YubiKey provider
| Feature | FIDO2 | YubiKey |
|---|---|---|
| Key types | Any FIDO2 key | YubiKey only |
| Protocol | CTAP2 hmac-secret | HMAC-SHA1 challenge-response |
| PIN support | Yes | No |
| Key output | 32 bytes | 20 bytes |
| Slot config | N/A | Slot 1 or 2 |
Choose fido2 if your key supports the hmac-secret extension. Choose yubikey if you specifically use YubiKey's HMAC-SHA1 challenge-response (configured via ykman otp chalresp).
Next steps
- Sync a local cache: use the hardware provider as an encryption target.
- Credential leases: protect credentials used to create temporary access.