Configuration Reference

Facelock reads its configuration from /etc/facelock/config.toml. FACELOCK_CONFIG overrides it only when the effective user is non-root. Every effective-UID-0 process ignores the environment; use an explicit --config where supported, or the default path.

All settings are optional. Facelock auto-detects the camera and uses sensible defaults. The annotated config file at config/facelock.toml in the repository serves as the canonical example.

[device]

Camera settings.

KeyTypeDefaultDescription
pathstring (optional)Auto-detectCamera device path (e.g., /dev/video2). When omitted, Facelock auto-detects the best available camera, preferring IR over RGB.
max_heightu32480Maximum frame height in pixels. Frames taller than this are downscaled to improve processing speed.
rotationu160Rotate captured frames. Values: 0, 90, 180, 270. Useful for cameras mounted sideways.
warmup_framesu322Frames to discard immediately after opening the camera to let exposure and gain stabilize. Device quirks may override this.
dark_thresholdf320.6Fraction of pixels that must be darker than dark_pixel_value before the frame is treated as unusably dark.
dark_pixel_valueu810Pixel brightness cutoff used by the dark-frame check.
ir_emitterboolfalseAttempt to enable a controllable IR emitter when the camera opens. Only needed for hardware that does not auto-enable its IR LED.
camera_release_secsu323Daemon only. Seconds to keep the camera streaming after a failed authentication so an immediate retry skips the reopen cost. Cancellation and errors release the camera at once, and so does a success unless camera_release_after_success_secs is set. 0 disables the hold entirely (it used to be silently substituted with 5).
camera_release_after_success_secsu320Daemon only. Seconds to keep the camera streaming after a successful authentication too. 0 (the default) releases it immediately — the interaction is over, and on IR hardware the emitter LED goes out with it. Set it only where privileged actions repeat with no authentication caching in front of them (sudo with a zero timestamp_timeout, a polkit action without auth_admin_keep), so each one is a fresh authentication that would otherwise pay a camera reopen. Failures still use camera_release_secs; cancellations and errors always release at once.

[recognition]

Face detection and embedding parameters.

KeyTypeDefaultDescription
thresholdf320.80Cosine similarity threshold for accepting a face match. Must be between 0.0 and 1.0. Higher values are stricter. See the range guide below.
timeout_secsu325Maximum seconds to attempt recognition before giving up. Must be > 0.
no_face_timeout_secsu322Seconds to keep scanning when no face at all has been detected. Once a face is seen, timeout_secs takes over — "seen, not matched yet" is the case worth waiting out. An empty-chair attempt ends early and charges no rate-limit budget. Clamped to timeout_secs (never an error); 0 disables the early exit.
detection_confidencef320.5Minimum confidence for the face detector to report a detection. Lower values detect more faces but increase false positives.
nms_thresholdf320.4Non-maximum suppression threshold for overlapping detections.
detector_modelstring"scrfd_2.5g_bnkps.onnx"ONNX detector model filename. Must exist in daemon.model_dir. Bundled models are verified against the manifest; custom models require detector_sha256.
detector_sha256string (optional)unsetRequired digest for a custom detector; bundled models use the manifest digest.
embedder_modelstring"w600k_r50.onnx"ONNX embedder model filename. Must exist in daemon.model_dir. Bundled models are verified against the manifest; custom models require embedder_sha256.
embedder_sha256string (optional)unsetRequired digest for a custom embedder; bundled models use the manifest digest.
execution_providerstring"cpu"ONNX Runtime execution provider. Values: "cpu", "cuda", "rocm", "openvino". GPU providers require a GPU-enabled ONNX Runtime package installed on the system.
threadsu324Number of CPU threads for ONNX inference.

Threshold range guide (ArcFace cosine similarity)

RangeDescription
0.30 -- 0.50Very loose -- high false accept rate, not recommended
0.50 -- 0.65Loose -- convenient but may accept similar-looking people
0.65 -- 0.80Balanced -- good for most setups, low false accept rate
0.80 -- 0.90Strict -- rarely accepts wrong person, may reject on bad angles
0.90+Very strict -- may require near-ideal lighting and pose

Run sudo facelock test to see your similarity scores, then set the threshold below your typical match score with some margin. Exit zero alone is not a match verdict; inspect the output.

Model tiers

TierDetectorEmbedderTotal sizeNotes
Standardscrfd_2.5g_bnkps.onnx (3MB)w600k_r50.onnx (166MB)~170MBFast, good accuracy (default)
Balancedscrfd_2.5g_bnkps.onnx (3MB)glintr100.onnx (249MB)~252MB~15-30ms slower, better recognition
High accuracydet_10g.onnx (17MB)glintr100.onnx (249MB)~266MB~40-50ms slower, best accuracy

Run sudo facelock setup to select a model tier interactively and download the required models. If you point detector_model or embedder_model at a custom file, you must also set the matching SHA256 so the daemon can verify it at load time.

[daemon]

Controls how the PAM module reaches the face engine.

KeyTypeDefaultDescription
modestring"daemon""daemon" connects to a persistent daemon via D-Bus system bus (models stay loaded; only a cold attempt pays a camera reopen -- measure it with sudo facelock bench camera-reopen). "oneshot" spawns facelock auth per PAM call (slower: model load on every call, no background process).
model_dirstring"/var/lib/facelock/models"Directory containing ONNX model files.
idle_timeout_secsu640Shut down the daemon after this many idle seconds. 0 means never. Useful with D-Bus activation.

[storage]

KeyTypeDefaultDescription
db_pathstring"/var/lib/facelock/facelock.db"SQLite database for face embeddings. File permissions should be 600, owned by root:root.

[security]

KeyTypeDefaultDescription
disabledboolfalseDisable face authentication entirely. PAM returns IGNORE, falling through to the next auth method.
abort_if_sshbooltrueRefuse face auth when connected via SSH (no camera available).
abort_if_lid_closedbooltrueRefuse face auth when the laptop lid is closed (camera blocked).
require_irbooltrueRequire an IR camera for authentication. RGB cameras are trivially spoofed with a printed photo. Only set to false for development/testing.
require_frame_variancebooltrueRequire multiple frames with different embeddings before accepting. Defends against static photo attacks.
frame_variance_max_similarityf320.985Maximum similarity between consecutive matched frames in the variance window. Passive anti-photo check only; it does not stop video replay.
ir_texture_min_stddevf3210.0Minimum raw-grayscale standard deviation for the IR texture check.
require_landmark_livenessboolfalseRequire landmark movement between frames to pass liveness check. Detects static images by tracking facial landmark positions across frames. Experimental; off by default.
landmark_displacement_pxf321.5Minimum pixel displacement for a landmark to count as "moving" between frames. Only used when require_landmark_liveness is true.
landmark_min_movingu323Number of facial landmarks (out of 5) that must show movement to pass the liveness check. Only used when require_landmark_liveness is true.
suppress_unknownboolfalseSuppress warnings for unknown users (users with no enrolled face).
min_auth_framesu323Minimum number of matching frames required before accepting. Only applies when require_frame_variance is true.
bind_templates_to_devicebooltrueSkip templates enrolled on a camera that does not match the live camera at the configured granularity. Advisory, not device attestation.
device_match_granularitystring"model""model" compares VID:PID; "unit" also requires a stable serial.
bind_legacy_templatesbooltruePermit older templates without a device identity, with a re-enrollment warning.
bind_device_aadboolfalseOpt-in cryptographic camera binding for encrypted templates; requires re-enrollment and a usable device identity.
allow_plaintextboolfalsePermit encryption.method = "none"; without it, plaintext enrollment is refused.

[security.rate_limit]

KeyTypeDefaultDescription
max_attemptsu325Maximum face-detected authentication failures per user per window; successful and no-face attempts do not consume this budget.
window_secsu6460Rate limit window in seconds.

[security.pam_policy]

KeyTypeDefaultDescription
allowed_serviceslist of strings[]If non-empty, only these PAM services may use facelock.
denied_serviceslist of strings[]PAM services that must always skip facelock, even if otherwise allowed.

[notification]

Controls how authentication feedback is delivered.

KeyTypeDefaultDescription
modestring"terminal"Notification mode. "off" -- no notifications. "terminal" -- PAM text prompts only. "desktop" -- desktop popups only (via D-Bus/notify-send). "both" -- terminal and desktop.
notify_promptbooltrueShow prompt when scanning starts ("Identifying face...").
notify_on_successbooltrueNotify on successful face match.
notify_on_failureboolfalseNotify on failed face match.

[snapshots]

Save camera snapshots on auth attempts for debugging or auditing.

KeyTypeDefaultDescription
modestring"off""off" -- never save. "all" -- every attempt. "failure" -- failed auth only. "success" -- successful auth only.
dirstring"/var/log/facelock/snapshots"Directory for snapshot JPEG images.

[encryption]

Controls how face embeddings are encrypted at rest.

KeyTypeDefaultDescription
methodstring"keyfile""keyfile" -- AES-256-GCM with a root-only key file. "tpm" -- AES-256-GCM with a TPM-sealed key. "none" requires security.allow_plaintext = true.
key_pathstring"/etc/facelock/encryption.key"Path to AES-256-GCM key file for keyfile method.
sealed_key_pathstring"/etc/facelock/encryption.key.sealed"Path to TPM-sealed AES key for tpm method.

With method = "tpm", the 32-byte AES key is sealed by the TPM at rest. At daemon startup, the key is unsealed and held in memory. Embeddings use the same AES-256-GCM format as keyfile — no re-encryption needed when migrating between methods. The root-gated migration commands are sudo facelock tpm seal-key (keyfile → tpm) and sudo facelock tpm unseal-key (tpm → keyfile). seal-key requires the plaintext key to exist and refuses to overwrite a sealed key; unseal-key requires the sealed key and refuses to overwrite a plaintext key. Each command updates encryption.method only after writing the destination key.

[polkit]

KeyDefaultDescription
face_eligible_actions["org.freedesktop.login1.lock-sessions"]Action IDs the optional agent may handle; it declines all others.

[pam]

KeyDefaultDescription
config_dirs["/etc/pam.d", "/usr/lib/pam.d"]Lookup order. Only the first directory is writable; later entries are vendor roots.

[audit]

Structured audit logging of authentication events.

KeyTypeDefaultDescription
enabledboolfalseEnable structured audit logging to JSONL file.
pathstring"/var/log/facelock/audit.jsonl"Path to the audit log file.
rotate_size_mbu3210Rotate the log file when it exceeds this size (in MB).

[tpm]

TPM 2.0 settings for sealing the AES encryption key. These settings apply when encryption.method = "tpm".

KeyTypeDefaultDescription
seal_databaseboolfalseSeal the SQLite database file with the TPM key in addition to the encryption key.
pcr_bindingboolfalseBind sealed key to boot state (PCR values).
pcr_indiceslist of u32[0, 1, 2, 3, 7]PCR registers to verify on unseal.
tctistring"device:/dev/tpmrm0"TPM Communication Interface.