Skip to content
irlume: face authentication for Linux

Your face unlocks Linux: login, sudo, the lock screen, and app prompts (Bitwarden, pkexec). Works in the dark, resists photo & screen spoofs, never stored as an image.

Works with the camera you have: an IR (Windows Hello) camera unlocks the full secure tier, a regular webcam gives convenient screen unlock, and a fingerprint reader slots in as a companion factor.

Built to match or beat Windows Hello, on a fully open, commercially clean stack.


License: GPL v3 Platform Built with Rust Packaged Version OpenSSF Scorecard OpenSSF Best Practices AI-assisted

Install · How it works · Security · Limits · FAQ · Docs


irlume demo: one-line install, guided face enrollment in the TUI, wiring the greeter and lock screen, and opt-in face-sudo

From a one-line install to a wired face login: guided face enrollment in the TUI, greeter and lock-screen wiring, and opt-in face-sudo.


✨ What you get

🌑 Works in the dark Active infrared recognition (Windows-Hello cameras); no ambient light needed.
🔒 Unlocks everything Login greeter, lock screen, sudo (opt-in via login enable --with-sudo), and app prompts like Bitwarden's biometric unlock via polkit (opt-in via login enable --with-polkit; approve with a deliberate nod, details), with the password always as fallback (no lockout, ever).
🙋 On-demand, by consent The camera fires only when you ask: leave the password field empty and press Enter. Typing a password never starts a scan. A grace window after the gesture (~15 s at login/lock, ~5 s for sudo) keeps retrying while you settle into frame, but never retries a failed match. Wiring is tailored per login manager (GDM · SDDM · Plasma Login · LightDM · greetd · COSMIC · ly).
🗝️ Opens your keyring On IR hardware a face match TPM-unseals your login password so the wallet unlocks at login, like Hello.
👁️ Real liveness Algorithmic IR anti-spoof gate + opt-in passive blink detection (no prompt, no action).
🧬 No face images stored Stores 512-D embeddings, never images; on TPM hardware they're AES-256-GCM encrypted under a TPM-sealed key (without a TPM: root-only files, and the TUI says so).
🎚️ Adapts to your hardware IR camera → Secure tier · RGB-only → Convenience (screen-unlock) tier · fingerprint reader → face OR fingerprint (coexist, either unlocks). All auto-detected.
🩺 Self-healing A live TUI (irlume tui) detects & one-key-fixes daemon/PAM/reader/config faults, and a systemd watcher re-applies the PAM wiring if a distro update (authselect / pam-auth-update) strips it.
📦 Self-contained One package per distro, all models bundled. git clone and go.

🆚 Comparison: Windows Hello, Howdy, visage

How irlume stacks up against Windows Hello and the Linux face-unlock projects you've probably met (Howdy, visage):

Windows Hello Howdy visage irlume
Liveness / anti-spoof IR only (bypassable: CVE-2021-34466) ❌ none; its own README warns a "well-printed photo of you could be enough" ⚠️ passive (landmark-stability; blocks photos, not video) ✅ algorithmic IR gate on by default (blocks screens and matte prints); opt-in passive blink adds a glossy-print/replay defense. Self-tested vs ISO/IEC 30107-3
Camera-injection defense device-trust (newer HW) ❌ none ❌ none ✅ device pinning + cross-spectrum RGB↔IR
Template protection TPM-bound enclave ⚠️ unencrypted encodings on disk AES-256-GCM, key in a 0600 disk file (not TPM-sealed) ✅ AES-256-GCM, TPM-sealed key (survives disk theft)
Opens your keyring/wallet (keyring stays locked) TPM-unseals it at login
Stores your face as… template encoding embedding embedding only, never an image
Model licensing proprietary MIT code · dlib weights ⚠️ non-commercial weights permissive, bundleable
Runs on Windows Linux Linux Linux: Fedora · Arch · Debian/Ubuntu · NixOS

The default IR gate blocks screens and matte prints (0% APCER in self-test), but a determined life-size glossy print passed it at 98.6% APCER; the opt-in passive-blink challenge closes that at the cost of a slower login. Enrollment on IR hardware offers to enable it. See Honest limitations.

📦 Install

v0.7.0. Works end-to-end on real hardware across all three families, including face-approved app prompts (Bitwarden). Not yet certified (no iBeta lab pass); see Honest limitations.

You need: x86-64 Linux with systemd & PAM; the distros below are packaged and tested. A TPM 2.0 is strongly recommended (encrypted templates, keyring unlock) but not required. Any camera works; it just sets your tier: IR camera → secure login · RGB webcam → screen unlock · fingerprint → companion.

One-step install

curl -fsSL https://raw.githubusercontent.com/archledger/irlume/main/scripts/install.sh | sh

Detects your distro and installs from the signed Copr repo (Fedora), the PPA (Ubuntu LTS), the AUR (Arch), or a checksum-verified release .deb (Debian 12+, Ubuntu derivatives). It installs a package only and wires nothing into your login, and it stops without changing anything if irlume is already installed (use irlume update to upgrade). Prefer to read it before running it?

curl -fsSL https://raw.githubusercontent.com/archledger/irlume/main/scripts/install.sh -o install.sh
less install.sh && sh install.sh

Or install manually with your package manager:

FedoraUbuntuArchDebian 12+
# Copr
sudo dnf copr enable \
  archledger/irlume
sudo dnf install irlume
# PPA
sudo add-apt-repository \
  ppa:archledger/irlume
sudo apt install irlume
# AUR
yay -S irlume
# .deb from Releases
sudo apt install \
  ./irlume_*.deb

Fedora and current-LTS Ubuntu update with the system (dnf upgrade / apt upgrade). The PPA carries the current Ubuntu LTS only; on an older LTS or a derivative (Mint, Pop!_OS, Zorin, elementary) use the universal Debian .deb from Releases; it needs glibc 2.35 or newer (Debian 12+, Ubuntu 22.04+, and their derivatives all qualify) and refuses to install on anything older. irlume update handles every case: it detects how irlume was installed and updates the same way.

On NixOS, add nixosModules.irlume from this flake instead; it runs the daemon and wires the PAM stacks declaratively. See docs/NIXOS.md.

Then, once:

irlume tui                         # enroll your face + configure, guided
sudo irlume login enable --apply   # opt-in: wire the greeter + lock screen

login enable (and the TUI's [w]) wires the greeter and lock screen for your login manager. From then on face is on-demand: at the greeter or lock screen, leave the password empty and press Enter. The camera fires only then. Face-sudo is a separate opt-in; add it with sudo irlume login enable --with-sudo --apply, since granting root by face is a trade-off worth choosing deliberately (the password always still works).

Full step-by-step (both the guided TUI and the individual CLI commands, with keyring unlock, recovery, and fingerprint): docs/SETUP.md. Every command and flag on one page: docs/COMMANDS.md. Something not working, or want to audit every decision? docs/DEBUGGING.md: irlume doctor runs the platform checks in one pass (TPM, Secure Boot, camera, models), irlume logs puts every face-auth journal line in one view, and sudo irlume logs debug on traces every pipeline stage (scores, liveness cues, thresholds, timings; numbers only, never frames or embeddings).

Usually no IR-emitter step is needed. Many Hello cameras drive their own illuminator whenever the infrared stream is open, and for the modules irlume has been validated against it applies the control those cameras document. Nothing runs on its own: if your infrared frames stay dark, sudo irlume ir-setup will look for a control, and it tells you first that it writes to your camera.

It only ever addresses the extension unit your camera's USB descriptor identifies as Microsoft's camera-control unit, only selectors that unit advertises, and only with values built from the camera's own answers. Before 0.7.1 it did something very different, and it destroyed a reporter's camera; see #159.

Safe to try. Installing the package wires nothing into your login. Auth only changes when you run login enable, and without --apply it's a dry run that prints the full per-file wiring plan without writing anything. Your password always keeps working, and one command undoes everything: sudo irlume login disable --apply.

irlume update checks for a new release the way your distro expects. Prefer to build from source? See packaging/ and scripts/install-host.sh.

🧠 How it works

Privilege separation first. The thin pam_irlume.so module and irlume CLI are untrusted clients of the privileged irlumed daemon, the only thing that ever touches the camera, IR emitter, models, templates, or TPM. They speak over a Unix socket authenticated with SO_PEERCRED.

flowchart LR
    subgraph U["Untrusted clients"]
        direction TB
        P["pam_irlume.so<br/>greeter · sudo · lock"]
        C["irlume CLI<br/>+ live TUI"]
    end
    subgraph D["irlumed · privileged daemon (root)"]
        direction TB
        CAM["Camera + IR emitter"]
        ML["YuNet + rescue → AuraFace<br/>IR liveness gate · matcher"]
        T["TPM seal · encrypted templates"]
    end
    P -->|"Unix socket · SO_PEERCRED"| D
    C -->|"Unix socket · SO_PEERCRED"| D
Loading

A login, end to end. Every branch that isn't a clean, live match falls back to the password; there is no lockout.

flowchart TD
    A["Greeter / lock screen:<br/>leave password empty, press Enter"] --> B["Camera fires, on demand<br/>captures RGB + IR in parallel"]
    B --> DET["Detect face<br/>YuNet → BlazeFace rescue"]
    DET --> L{"IR liveness gate<br/>relief ratio · reflectance · glint"}
    L -->|spoof or no face| PW["Type your password<br/>no lockout, ever"]
    L -->|live| M{"Match embedding<br/>at or above threshold?"}
    M -->|no| PW
    M -->|yes| G["Grant<br/>+ TPM-unseal your keyring"]
Loading

Model bill-of-materials. Every weight is permissive or first-party, all GPLv3-compatible, so the whole thing is bundleable:

Stage Model License
Detection YuNet MIT
Detection rescue BlazeFace short-range (fires only on a YuNet miss) Apache-2.0
Recognition AuraFace (512-D ArcFace) Apache-2.0
IR liveness gate self-built, algorithmic (no weights) n/a
Passive blink liveness + rescue alignment MediaPipe FaceMesh (478-pt) → eye-aspect-ratio (opt-in) Apache-2.0
IR domain match raw AuraFace + per-enrollment on-device calibration (fitted from your own scans; no third-party data, ADR-0004) n/a

More depth: Architecture · Threat model · Standards mapping · Cross-distro notes.

🔐 Your face never leaves as an image

irlume stores only 512-D embeddings (a one-way projection; you can't rebuild a photo from it), AES-256-GCM encrypted, under a key the TPM seals to your boot state. We audited this live:

  • 🧑‍💻 A normal user account → catting the files gives Permission denied (root-only, 0600).
  • 💽 Disk-theft test: copied the encrypted templates and the sealed key to a second machine with its own TPMtpm: integrity check failed. The stolen data is undecryptable off the original box.

The delta vs Hello: Hello isolates templates in a VBS/TPM enclave the kernel never sees; irlume's daemon is a root process holding decrypted embeddings in RAM during a match, so root on the live machine is the trust boundary (as with most Linux secrets). Full write-up: docs/SECURITY_AT_REST.md.

Every claim here maps to something you can run on your own machine: docs/VERIFY.md.

⚖️ Honest limitations

The current gaps:

  • Passive blink liveness is a deterrent, not a guarantee. It closes casual and typical print/screen attacks, but a determined life-size glossy print still slips through occasionally, and it doesn't cover glasses-wearers (IR lens reflections hide the eyelid). Every miss falls safely to the password. Beating a determined glossy print is the passive-cue ceiling; it needs a trained PAD model or true depth hardware. See ADR-0002 and the PAD self-test results.
  • RGB-only laptops get the Convenience tier: face unlocks the screen only, never sudo, login, or the keyring (those keep the password). By design.
  • Bright IR behind you defeats the relief check. The anti-spoof gate infers shape from how the IR emitter's light falls across the face; when the scene's own infrared floods it, no such signal is left, and a genuine face is rejected to the password. It is a brightness ratio, not a range measurement: the sensor does not measure distance, and a glossy print with a hot centre passes it. Measured in a 430-sample field session (2026-07-16, cloudy-bright sky): reliable below ambient ~120 on the 0-255 IR scale (indoors, inside vehicles, shade, a closed car with 20% tint passed 99/99), marginal to ~170, and 0/129 genuine samples passed above ~170 (open sky or sun behind the user; the emitter's contribution fell to noise and 46-82% of the IR frame was saturated). irlume can't tell sky from a bright lamp (both are just infrared), so the rejection names the condition and the fix: turn away from the light, or type the password.
  • Not lab-certified. We self-test against ISO/IEC 30107-3; there's no paid iBeta pass. Demographic FMR tuning (FAIRNESS.md) is ongoing.

❓ FAQ

Is this "Windows Hello for Linux"?

Yes, that's the bar. irlume brings Windows Hello-style face login to Linux: face-unlock the login screen, lock screen, sudo, and your keyring/wallet, using the same IR (Windows Hello) camera your laptop already has. And it aims past Hello where Hello is weak: real anti-spoof liveness, encrypted TPM-sealed templates, and a fully open stack.

How is irlume different from Howdy?

Howdy is the best-known face unlock for Linux, and it's honest about being a convenience: its README says a well-printed photo of you could be enough to fool it. irlume is built as an authenticator: an IR liveness gate (self-tested against ISO/IEC 30107-3), AES-256-GCM-encrypted templates under a TPM-sealed key, camera pinning, and TPM keyring unlock at login, with tiers, so RGB-only face match is deliberately limited to screen unlock. See the comparison.

Do I need an IR camera?

No. An IR (Windows Hello) camera gets the full Secure tier: greeter login, sudo, keyring unlock, works in the dark. A regular RGB webcam gets the Convenience tier: face unlock for the lock screen only. A fingerprint reader works as a companion factor on either. All auto-detected.

Is this AI-generated?

AI-assisted, human-directed, and disclosed throughout the git history: the large majority of commits carry Co-Authored-By trailers naming the AI assistant (Anthropic's Claude, also visible under this repo's contributors). A human maintainer sets direction, reviews the changes, and validates every release with clean-slate installs on real hardware (Fedora, Arch, Ubuntu; IR camera, TPM, fingerprint) before anything ships. Judge the project by its verifiable artifacts: the threat model, measured error rates, spoof-test results, and the code itself are all in the repo, reproducible regardless of what tools wrote them.

Can I verify these claims myself?

That's the point of docs/VERIFY.md. Each claim maps to a command you can run: see your own camera's anti-spoof score, confirm the stored template is encrypted ciphertext (not an image), run the presentation-attack self-test against your own spoofs, reproduce the real-face FAR on LFW, and build and run the test suite. Some checks take two minutes, some take real effort, but every one is runnable.

Glasses, beards, outdoors: when should I re-enroll?

One enrollment usually lasts. A profile is one identity, and a face can only own one profile, so different looks of the same person are extra scans on that profile, not a second profile. Wear glasses sometimes? Add a scan with Improve Recognition (TUI Profiles → [a], or irlume profiles add-scan) while wearing them. Major appearance change (shaved beard, new heavy frames)? Same thing, add a scan rather than starting over. Recognition flaky in bright sunlight? Strong ambient IR can wash out the emitter's illumination; add a scan captured in that environment. Profiles are per-user and deletable any time.

Does it work on Ubuntu / Fedora / Arch, GNOME / KDE, Wayland?

It does. irlume authenticates through PAM, and tailors the greeter wiring to the login manager it detects. Validated live on real machines: Fedora KDE end-to-end on IR hardware (Plasma Login Manager greeter, lock screen, sudo, TPM keyring unlock; Wayland), Ubuntu GNOME on an RGB+fingerprint laptop (lock-screen face unlock, fingerprint, correct password-only refusals for login/sudo), and the full login-manager matrix: GDM (on-demand on GNOME ≥ 46; face-first before that), SDDM, LightDM (gtk and slick greeters, X11), greetd (tuigreet), and COSMIC's greeter. Arch is validated for packaging, install, and the full CLI/daemon stack (that testbed has no camera). Reports from other hardware are very welcome.

I changed my login password and now my keyring/wallet won't open

This is general Linux behaviour, not specific to irlume. Changing your login password (passwd or a settings dialog) updates /etc/shadow, but it does not re-encrypt your KWallet / GNOME keyring. The wallet keeps the key derived from your old password until you change the wallet's password separately, so it no longer matches the new login password.

irlume seals whatever password you armed and hands it to the wallet, so it passes along the old one and cannot fix this by itself. To bring all three back in sync after a password change:

  1. Login password is already updated by passwd.
  2. Wallet password: change it to the new one in KWallet Manager → "Change Password" (KDE), or Seahorse → the "Login" keyring → "Change Password" (GNOME).
  3. irlume's sealed copy: run irlume keyring arm to re-seal the new password.

Rule of thumb: whenever the wallet password changes, re-run irlume keyring arm so irlume's seal keeps matching it. Your typed password opens everything in the meantime, so nothing locks you out.

How fast is a face login, and why is the blink challenge slower?

A normal face login takes about 2.5 seconds on an integrated IR camera (measured on an ASUS Zenbook, CPU inference). Most of that is opening the camera and letting auto-exposure settle, not the neural networks. The RGB and IR captures run in parallel, which cuts the capture stage by about a third; docs/DEBUGGING.md shows how to time every stage on your own hardware.

The opt-in blink challenge (irlume profiles challenge on) is a deterrent against a glossy print or vinyl that mimics the infrared relief pattern: it watches for a natural blink, which a static image cannot do. Detecting a blink is inherently temporal, so it captures a roughly 5-second infrared sequence, and the login takes about 10 seconds (measured across six runs, glasses on and off). That is the trade: the challenge closes a spoof gap the default single-frame gate cannot, at about four times the latency.

It is off by default. Turn it on with irlume profiles challenge on if you want the extra deterrent, or leave it off for the ~2.5-second login; the default IR-structure gate already rejects photos, screens, and video replays.

📚 Documentation

I want to… Go to
Install and set up, guided or by hand docs/SETUP.md
Look up every command and flag docs/COMMANDS.md
Write software that drives irlume docs/INTEGRATION.md
Look up the versioned machine API, field by field docs/MACHINE-API.md
Understand the architecture docs/ARCHITECTURE.md
Read the threat model and standards mapping docs/THREAT_MODEL.md · docs/STANDARDS.md
Verify the claims on my own machine docs/VERIFY.md
Debug a login or trace every stage docs/DEBUGGING.md
Contribute and set up a dev shell CONTRIBUTING.md · docs/DEVELOPMENT.md
Run it on NixOS docs/NIXOS.md
See what changed in each release CHANGELOG.md

🛠️ Status

v0.7.0: working and validated on real hardware. Fedora runs the full IR Secure tier end to end, including face-approved app prompts (Bitwarden biometric unlock via polkit, verified live); Ubuntu / Pop!_OS runs the RGB Convenience tier plus a fingerprint; Arch is validated for packaging and the CLI/daemon on a camera-less testbed. Packaged for all three families (Copr · AUR · PPA). Interfaces may still shift before 1.0.

  • Presentation attacks tested and denied on a NexiGo N930W: printed photo (including in direct sunlight), laptop screen, phone screen at full brightness, and a video replay with real head motion. All rejected at the infrared stage; a physical 3D mask is not yet tested (contributions welcome).
  • TPM sealing picks the strongest tier the machine supports (signed-PCR → pcrlock → literal PCR-7) and round-trip-verifies it before trusting it, so a policy that cannot unseal on this boot never holds the secret.
  • 🧪 Self-tested against ISO/IEC 30107-3; not lab-certified (no iBeta pass). Demographic FMR tuning (FAIRNESS.md) is ongoing.
  • 🧰 Contributor-ready: a reproducible Nix dev shell and developer guide; CI runs fmt / clippy / build / test on every push and PR.

The per-release detail (0.1.x through 0.7.0) lives in CHANGELOG.md.

🙏 Credits

irlume relies on models and code from other projects. The bundled models:

  • YuNet (OpenCV Zoo, MIT) detects faces in both the RGB and IR streams.
  • AuraFace by fal (Apache-2.0) is the 512-D ArcFace recognizer; irlume ships only its glintr100.onnx.
  • MediaPipe FaceLandmarker mesh (Google, Apache-2.0) supplies the 478 dense landmarks behind the opt-in blink liveness and refines rescue detections into alignment points.
  • MediaPipe BlazeFace short-range (Google, Apache-2.0) is the detection-rescue stage: it runs only when YuNet finds no face, such as sun-saturated frames.

The TPM and camera code builds on:

  • rust-tss-esapi (the Parsec project, Apache-2.0) wraps the TPM 2.0 ESAPI. irlume builds from a small patch branch that adds the PolicyAuthorizeNV wrapper (upstream PR #486) plus the PR #530 session-leak fix, pinned to an exact commit.
  • systemd (LGPL-2.1-or-later): the Tier-2 pcrlock seal and unseal in crates/irlume-core/src/tpm.rs follows the scheme in systemd's src/shared/tpm2-util.c and src/pcrlock/pcrlock.c.
  • linux-enable-ir-emitter first showed that the 850nm emitter on integrated Hello cameras can be driven from userspace over UVC Extension Units. irlume no longer uses its search technique: irlume's own version of it destroyed a camera (#159), and upstream gates that search behind an interactive warning about firmware corruption that irlume did not have.
  • ort binds Microsoft's ONNX Runtime, which irlume loads at runtime for every model above.

Prior art that shaped the design: Windows Hello for the infrared, dual-sensor credential model, and Howdy and visage as the existing Linux face-unlock projects (see the comparison). irlume is the from-scratch successor to the author's earlier linhello.

Windows and Windows Hello are trademarks of Microsoft Corporation. irlume is an independent project, not affiliated with, sponsored by, or endorsed by Microsoft; the marks are used only to describe compatibility and prior art.

🤝 Contributing & license

GPL-3.0-or-later, fully open, copyleft: modifications stay free, nobody can lock this down. Contributions welcome under the DCO; no CLA, no commercial relicensing. Security reports: see SECURITY.md.

Questions, setup help, hardware reportsGitHub Discussions. Reports from laptops with IR cameras (working or not) are the most valuable contribution right now. Bugs → Issues.

Note

AI disclosure: assisted, human-directed. irlume is built by a human maintainer working with an AI assistant (Anthropic's Claude), disclosed throughout the git history via Co-Authored-By trailers; see the log or the contributors page. Direction, review, and releases are human-driven; every release is validated with clean-slate installs on real hardware, and the security claims rest on reproducible evaluations in this repo, not on who typed the code.

Built with Rust · GPL-3.0-or-later · your face stays yours