Face authentication for Linux. Windows Hello-style facial recognition with IR anti-spoofing, sub-second daemon-mode latency, and complete privacy -- all authentication runs locally on your hardware with no telemetry. After initial model download, Facelock never touches the network.
SCRFD detection finds faces, affine alignment normalizes geometry, and ArcFace produces a 512-dimensional embedding for cosine similarity matching.
V4L2 frame acquisition with auto-detection. Prefers IR cameras for anti-spoofing. CLAHE enhancement for consistent lighting.
SCRFD neural network locates faces and extracts 5-point landmarks. Affine alignment produces a normalized 112x112 crop.
ArcFace produces a 512-dim L2-normalized vector. Cosine similarity against stored embeddings determines match or reject.
A complete face authentication stack written in Rust, designed for the Linux PAM ecosystem.
Enforces infrared cameras by default. Phone screens and printed photos lack IR skin texture, blocking the most common attack vector.
Persistent daemon keeps ONNX models loaded. ~600ms typical, dropping to ~150ms on back-to-back auths when the camera stays warm.
All processing happens on-device via ONNX Runtime. No cloud services, no network requests, no telemetry, no analytics. Your face data never leaves your machine, ever.
Drop-in PAM module for sudo, polkit, and login. Installs as a single pam_facelock.so with one line in your PAM config.
Optional TPM 2.0 support for encrypting face embeddings at rest. Hardware-bound keys ensure biometric data stays protected.
Choose persistent daemon mode for speed or oneshot mode for simplicity. The CLI auto-detects which mode is available.
Multiple independent layers protect against spoofing, tampering, and unauthorized access.
Enabled by default. Rejects RGB cameras that are trivially spoofed with a printed photo. IR captures skin texture invisible to screens.
Requires micro-movement between consecutive frames. Static photos produce near-identical embeddings and are rejected automatically.
5 attempts per user per 60 seconds by default. Prevents brute-force and rapid-retry attacks against the daemon.
ONNX model files are SHA256-verified at every load. Tampered models are rejected before any inference runs.
D-Bus system bus policy restricts daemon access. Only root and facelock group members can send messages to the daemon interface.
Every authentication attempt is logged to syslog with user, service, and outcome. Full audit trail in journald or /var/log/auth.log.
Facelock is designed from the ground up to keep your biometric data private.
Face detection and recognition run entirely on your CPU or GPU via ONNX Runtime. No images or embeddings are ever transmitted over the network.
Zero analytics, tracking, or phone-home code. Models are downloaded once during facelock setup -- after that, Facelock never contacts any server.
Face embeddings can be encrypted with AES-256-GCM, optionally sealed to your TPM. Even if someone copies your database, the biometric data is unreadable.
Every line of code is MIT/Apache-2.0 licensed. No proprietary blobs, no obfuscated network calls. Verify the privacy claims yourself.
Build from source, download models, enroll your face, and enable PAM authentication.
Also available as .deb, .rpm, and Nix flake. See docs for details.
Facelock is a ground-up rewrite of the Howdy concept, built in Rust with security as a first-class concern.
| Feature | Facelock | Howdy |
|---|---|---|
| Language | Rust | Python |
| Daemon mode | Yes (~150-600ms auth) | No (process per auth) |
| IR enforcement | Default on | Not enforced |
| Frame variance check | Default on | No |
| TPM encryption | Optional | No |
| Model verification | SHA256 at every load | No |
| Rate limiting | 5/user/60s | No |
| D-Bus activation | D-Bus activation | No |
| Constant-time matching | subtle crate (no timing leaks) | No |
| GPU acceleration | CUDA / ROCm / OpenVINO (runtime) | No |
| Audit logging | Structured JSONL + syslog | No |
| systemd hardening | ProtectSystem, NoNewPrivileges, etc. | No |
| PAM module size | ~2MB (no heavy deps) | Full Python runtime |