NetStacksNetStacks

Touch ID Vault Unlock (macOS)

Enable Touch ID for the NetStacks local vault: how the master password is wrapped in the macOS Keychain via LAContext, the self-healing fallback, and the security model.

Overview

On a Mac with Touch ID, NetStacks can unlock the local credential vault with your fingerprint instead of making you type the master password every time you launch the app. The master password still exists — Touch ID simply unwraps a copy of it that NetStacks keeps in the macOS Keychain, then feeds it into the normal unlock flow.

This feature is:

  • Local-only. It applies to the standalone NetStacks Terminal running in Personal mode against its built-in local vault. It is not available when the Terminal runs in enterprise mode against a Controller — the Touch ID controls are hidden and the API short-circuits.
  • macOS-only. The implementation is gated to target_os = "macos". On Windows and Linux every Touch ID call is a graceful no-op or returns an "unsupported" result, so the UI never offers the option.
  • Opt-in. Nothing is stored in the Keychain until you explicitly enable Touch ID and confirm with your master password.
Touch ID is a convenience layer, not a second factor

Enabling Touch ID does not change how your credentials are encrypted. They are still protected with AES-256-GCM under an Argon2id key derived from your master password. Touch ID just changes how you present that password at unlock time.

Requirements

The "Enable Touch ID" control only appears when all of the following hold:

  • You are running the standalone NetStacks Terminal in Personal mode (a local vault, not a Controller connection).
  • The build is running on macOS — the agent reports supported: true.
  • The Mac has biometrics enrolled (at least one fingerprint registered in System Settings → Touch ID & Password).
  • The vault is currently unlocked. Enrollment requires confirming your master password, so you enable it from inside the app after unlocking, in Settings → Credential Vault.

A Touch ID-equipped Mac (or a connected Magic Keyboard with Touch ID) is required. If no fingerprint is enrolled at the OS level, the pre-flight check fails and NetStacks reports that Touch ID is unavailable.

Enabling Touch ID

To turn on Touch ID unlock:

  1. Unlock the vault with your master password as usual.
  2. Open Settings and find the Credential Vault section.
  3. Under Touch ID Unlock, click Enable Touch ID.
  4. Re-enter your master password to confirm enrollment, then click Enable.
  5. macOS shows a Touch ID prompt reading "Enable Touch ID for the NetStacks vault". Place your finger on the sensor.

On success the status flips to "Enabled — you can use Touch ID on the unlock screen."

Behind the scenes, NetStacks first verifies the password you typed by actually unlocking the vault with it, then prompts for Touch ID, then stores the password in the Keychain and records the toggle. Confirming the password up front means an incorrect password can never be filed away in the Keychain.

Anyone enrolled on the Mac can unlock NetStacks

The enrollment screen warns you explicitly: any fingerprint registered on this Mac will be able to unlock NetStacks once Touch ID is enabled. Touch ID is bound to the device's biometric set, not to a specific person. Only enable it on a Mac whose enrolled fingerprints you trust.

Unlocking with Touch ID

Once enabled, the unlock screen at app launch detects that Touch ID is available and automatically fires the prompt the first time the screen appears. You should see the system Touch ID dialog reading "Unlock the NetStacks vault".

  • Success: the vault unlocks and the app loads — no typing required.
  • Cancel: if you dismiss the prompt, NetStacks does not loop you back into another prompt. It quietly drops you onto the master-password field so you can type your password instead. A guard ensures the auto-prompt fires at most once per screen visit.
  • Manual retry: an Unlock with Touch ID button remains on the screen so you can re-trigger the prompt after a cancel.

The Touch ID prompt is strict biometric only — it will not fall back to your macOS account password inside the system dialog. Your NetStacks master password remains the recovery path, and it lives on the same unlock screen.

The vault always re-locks on restart

The local vault is locked whenever the app restarts; it is never left unlocked across launches. Touch ID does not weaken that — it just makes re-unlocking a one-touch operation instead of a typed password.

Disabling Touch ID

To turn Touch ID off, unlock the vault, open Settings → Credential Vault, and click Disable Touch ID under the Touch ID Unlock section.

Disabling does not require a fingerprint — removing your own stored password from your own Keychain shouldn't demand biometric authentication. NetStacks deletes the Keychain entry and clears the vault.biometric_enabled setting. The next launch falls back to the master-password screen.

Disabling is safe to call even if nothing is stored

The delete operation is idempotent. If the Keychain entry was already removed (for example by macOS Keychain Access, or by the self-healing path described below), disabling still succeeds and simply clears the toggle.

How It Works Under the Hood

NetStacks stores the master password as a standard generic-password item in the macOS Keychain and gates every read and write behind an explicit Touch ID check that it drives itself with LAContext.evaluatePolicy.

The Keychain item

The password is filed under a fixed service and account name so it is findable from the command line:

Service:  com.netstacks.terminal.vault
Account:  master_password

You can confirm an entry exists with the macOS security tool (it will prompt for Keychain access):

# Does a NetStacks vault Keychain item exist? (-g prints the secret)
security find-generic-password -s "com.netstacks.terminal.vault" -a "master_password"

# Remove it manually (equivalent to Disable Touch ID in Settings)
security delete-generic-password -s "com.netstacks.terminal.vault" -a "master_password"

The biometric gate

On every store and retrieve, NetStacks creates an LAContext and evaluates the LAPolicyDeviceOwnerAuthenticationWithBiometrics policy. This is the strict "biometrics only" policy — there is no system-password fallback inside the prompt. A pre-flight canEvaluatePolicy call ensures the device actually has biometrics enrolled before the prompt is shown; if it doesn't, you get a clear "Touch ID is unavailable" error rather than a dead prompt.

The biometric reason strings shown by macOS are:

  • "Enable Touch ID for the NetStacks vault" — shown when enrolling.
  • "Unlock the NetStacks vault" — shown when unlocking.
Why not kSecAttrAccessControl / BiometryCurrentSet?

macOS's built-in biometric ACL (the access-control flag that ties a Keychain item to the current biometric set) only works with the Data Protection Keychain, which requires the binary to be code-signed with a keychain-access-groups entitlement. Unsigned development builds get errSecMissingEntitlement (-34018) from SecItemAdd. Driving the Touch ID check directly via LAContext gives the same prompt UX and works in any build, signed or not. A signed production build can layer the Data Protection ACL on top later without changing the user experience.

Self-Healing & Fallback

There is no separate "the master password changed, update Touch ID" step to remember. The unlock endpoint heals itself.

When you unlock with Touch ID, NetStacks:

  1. Prompts for Touch ID and retrieves the stored password from the Keychain.
  2. Feeds that password into the normal vault unlock.
  3. If the unlock succeeds, you're in.
  4. If the unlock fails — almost always because the master password was rotated elsewhere — NetStacks deletes the stale Keychain entry and clears the vault.biometric_enabled setting, then surfaces the error. The next launch shows a clean master-password screen, and you can re-enable Touch ID after unlocking.
Rotating your master password disables Touch ID

If you change your master password, the Keychain still holds the old one. The first Touch ID unlock after the change detects the mismatch, wipes the stale entry, and turns the toggle off. This is by design — simply re-enable Touch ID once and it will store the new password.

The status the UI uses is conservative: Touch ID is reported as enabled only when both the setting is on and a Keychain entry actually exists. If the entry is removed out from under NetStacks (for example via Keychain Access), the enabled flag automatically reads false on the next status check.

Security Model

Understanding what Touch ID does and does not protect:

Encryption is unchanged
Your credentials are still encrypted with AES-256-GCM under an Argon2id-derived key. Touch ID changes the unlock gesture, not the cryptography.
The master password is stored in the Keychain
When Touch ID is enabled, a copy of your master password lives in the macOS login Keychain as a generic-password item. It is protected by macOS Keychain encryption (tied to your macOS login) plus the NetStacks-driven Touch ID gate on read.
The threat NetStacks accepts
Because the item is a generic-password (not a Data Protection item with a hardware ACL), a process running as the same macOS user could in principle read the item without going through the NetStacks Touch ID gate. This is documented as a deliberate trade-off: a smaller risk than offering no biometric option at all, and acceptable for a local network-engineer tool. It does not expose anything to other users on the machine or to the network.
Strict biometrics, no PIN fallback
The prompt uses biometrics-only policy. There is no "enter your Mac password instead" button inside the system dialog. The recovery path is always your NetStacks master password on the unlock screen.
Anyone enrolled can unlock
Touch ID authorizes against the Mac's biometric set, so any registered fingerprint works. Treat enabling Touch ID as "anyone who can unlock this Mac biometrically can open my vault."
Disable Touch ID before lending or decommissioning a Mac

If you hand the machine to someone else, disable Touch ID first (which removes the Keychain entry), or rotate your master password — the next Touch ID attempt will then self-heal and clear the stale entry. Don't rely on the old password lingering in the Keychain being harmless.

Local Agent API

The Touch ID controls in the UI are backed by four endpoints on the local agent. They are meaningful only on macOS in Personal mode; in enterprise mode the frontend short-circuits and never calls them. The agent listens on 127.0.0.1 over a localhost TLS sidecar (loopback only by default), so these are local calls from the app itself.

Check status (no Touch ID prompt)

GET /vault/biometric/status is safe to call on any screen, including the locked one — it never triggers the biometric prompt.

// GET /vault/biometric/status  ->  200 OK
{
  "supported": true,   // build can do biometric unlock (macOS)
  "enrolled":  true,   // a Keychain entry currently exists
  "enabled":   true    // setting is on AND a Keychain entry exists
}

Enable enrollment

POST /vault/biometric/enable verifies the password by unlocking, prompts for Touch ID, stores the password in the Keychain, and flips the setting on. Returns 204 No Content.

// POST /vault/biometric/enable
{
  "password": "your-master-password"
}
// 204 No Content on success

Unlock with Touch ID

POST /vault/biometric/unlock triggers the Touch ID prompt, retrieves the password, and unlocks the vault. On a stale-password mismatch it self-heals (deletes the entry, clears the setting) before returning the error.

# Conceptual call (the app makes this over its localhost TLS sidecar)
# POST /vault/biometric/unlock  ->  204 No Content
#
# Error responses carry a machine-readable code, e.g.:
#   { "code": "BIOMETRIC_CANCELLED",     "error": "User cancelled the biometric prompt" }
#   { "code": "BIOMETRIC_NOT_ENROLLED",  "error": "No biometric enrollment exists for the vault" }
#   { "code": "BIOMETRIC_UNSUPPORTED",   "error": "Biometric unlock is not supported on this platform" }
#   { "code": "BIOMETRIC_ERROR",         "error": "..." }

Disable enrollment

DELETE /vault/biometric removes the Keychain entry and clears the setting. No Touch ID prompt. Idempotent — succeeds even if no entry exists. Returns 204 No Content.

Error codes the UI handles specially

BIOMETRIC_CANCELLED is treated as a silent fall-through to the password field (no error banner). BIOMETRIC_NOT_ENROLLED tells you the enrollment was removed and to re-enable after unlocking. All other codes surface the message and invite you to use your master password.

Questions & Answers

Does Touch ID replace my master password?
No. It stores and re-presents the same master password for you. The password is still the root secret and the only recovery path. Don't forget it.
Is Touch ID available on Windows or Linux?
No. The implementation is macOS-only (Touch ID via the Keychain and LAContext). On other platforms the controls don't appear and the API reports supported: false.
What about Windows Hello or fingerprint readers on Linux?
Not currently supported. Only macOS Touch ID is wired up today. On those platforms you unlock with your master password.
I changed my master password and Touch ID stopped working. Bug?
Expected behavior. The stored copy was the old password, so the first unlock after a rotation mismatches, self-heals (deletes the stale entry, clears the toggle), and asks for your password. Just re-enable Touch ID once after unlocking.
Can someone else on my Mac unlock my vault?
Any fingerprint enrolled on the Mac can satisfy the Touch ID prompt. Treat Touch ID as "anyone who can biometrically unlock this Mac can open my NetStacks vault." If that isn't acceptable, leave Touch ID off.
Where exactly is the password stored?
In the macOS Keychain as a generic-password item under service com.netstacks.terminal.vault, account master_password. You can inspect or delete it with the security CLI.
Does enabling Touch ID send my password anywhere?
No. Everything stays on your machine — the password goes into the local Keychain and the unlock happens against the local vault. NetStacks Personal mode is zero-telemetry; nothing leaves the device.
Why does the unlock screen sometimes prompt automatically and sometimes not?
It auto-fires the Touch ID prompt at most once each time the unlock screen appears, only when Touch ID is supported, enrolled, and enabled. If you cancel, it won't re-prompt automatically — use the Unlock with Touch ID button or type your password.

Troubleshooting

The "Enable Touch ID" option doesn't appear

Confirm you are on macOS, in Personal mode (local vault, not a Controller), the vault is unlocked, and the Mac has at least one fingerprint enrolled in System Settings. The control only shows when the agent reports supported: true.

"Touch ID is unavailable" when enabling or unlocking

The pre-flight canEvaluatePolicy check failed — usually no fingerprint is enrolled at the OS level, or biometrics are temporarily locked out (too many failed attempts; macOS requires your account password to re-arm Touch ID). Enroll/verify a fingerprint in System Settings, then try again.

Touch ID unlock fails and asks for my password

If the stored password no longer matches the vault (typically after a password rotation), NetStacks deletes the stale Keychain entry and clears the toggle. This is the self-healing path — unlock with your master password, then re-enable Touch ID.

I want to remove the stored password manually

Disable Touch ID in Settings, or delete the Keychain item directly:

security delete-generic-password \
  -s "com.netstacks.terminal.vault" \
  -a "master_password"

I forgot my master password

Touch ID can't recover it — it only re-presents a password you already set. Without the master password the encrypted data can't be decrypted. Your only path is to wipe the vault and start fresh; see the Credential Vault page for the wipe flow.