1. What are FIDO U2F and FIDO2?
FIDO U2F and FIDO2 are authentication standards from the FIDO Alliance that use public-key cryptography instead of reusable shared secrets. The private credential remains on the authenticator, such as a hardware security key, while the relying system stores only public registration data.
FIDO U2F
FIDO U2F, or Universal 2nd Factor, is the older model. It is primarily used as a second factor: the user enters a normal password first, then proves possession of the hardware token by touching or activating it.
FIDO2
FIDO2 is the newer model. It supports stronger authenticator behavior, including PIN-backed and potentially passwordless authentication. Depending on the token and software stack, FIDO2 can support a flow where the security key effectively replaces the account password.
| Feature | FIDO U2F | FIDO2 |
|---|---|---|
| Common use | Second factor after a password | Passwordless or strong hardware-backed login |
| Typical user flow | Password + token touch | Token PIN and/or biometric + token touch |
| Protocol family | CTAP1 / U2F | CTAP2 and WebAuthn |
| Linux PAM use in this guide | Not the preferred target | FIDO2 PIN + physical touch for selected users |
2. Authentication design used by this guide
This guide uses a group-gated local policy:
- Users in
fido-loginauthenticate with FIDO2 token PIN + physical touch only. - Users not in
fido-login, such as a controlled breakglass/local-admin account, remain password-only. - FIDO users do not fall back to Unix password if FIDO fails.
auth [success=ignore default=1] pam_succeed_if.so quiet user ingroup fido-login
auth [success=done default=die] pam_u2f.so authfile=/etc/security/u2f_keys cue pinverification=1 userverification=0
cue="FIDO users: enter token PIN…". That does not work: PAM splits module arguments on whitespace and treats the quotes as ordinary characters, so the module receives cue="FIDO, users:, enter… — a string of unrecognised options rather than one cue message. To pass an argument containing spaces, PAM requires square brackets:
auth [success=done default=die] pam_u2f.so authfile=/etc/security/u2f_keys cue [cue_prompt=FIDO users: enter token PIN, then touch token when it flashes] pinverification=1 userverification=0
This lab deliberately uses plain
cue instead. cue_prompt is not mentioned in the upstream changelog, so which 1.x release introduced it is unclear, and Mint 21's libpam-u2f 1.1.1 is old enough that assuming it would be a gamble on a machine students must log back into. Plain cue is documented in upstream's own examples and works across every 1.x. You lose the custom wording; you keep a login that works. Verify on the VM before the event man pam_u2f | grep -c cue_prompt — if that returns non-zero, the bracket form above is available and you may use it.sufficient with nouserok. That combination can accidentally allow unmapped users to bypass password authentication. This guide avoids that pattern.3. Assumptions, placeholders, and safety preconditions
Replace these placeholders before running commands:
| Placeholder | Meaning |
|---|---|
FIDO_USER | The normal local user who will use the FIDO token. |
BREAKGLASS_USER | A separate, known-working, sudo-capable local account that remains password-only. |
/dev/hidraw1 | The FIDO token device path shown by fido2-token -L. The number may differ on your system (hidraw0, hidraw2, etc.) depending on other HID devices present — always confirm with fido2-token -L rather than assuming hidraw1. |
sudo -v. Keep that account out of fido-login.- Keep a root-capable terminal or TTY recovery path available while testing.
- Do not modify
/etc/pam.d/loginin this walkthrough. Console TTY password login is your recovery path. - Back up each PAM file before editing it. The commands below include backup steps.
- Do not close your working session until LightDM, sudo, and screen unlock have all been tested.
4. Command style in this guide
Command blocks are copy-pasteable and do not include shell prompt characters. The label above each block tells you whether it is intended for a normal user shell, a sudo command, or a PAM snippet.
VirtualBox: enable USB passthrough for the FIDO token
If you are running Linux Mint inside VirtualBox, the FIDO token must be explicitly passed through to the VM before the guest OS can see it. VirtualBox does not pass USB devices to a VM by default.
fido2-token -L will return no devices even if the token is physically inserted.- With the VM powered off, open VirtualBox Manager and select your VM.
- Click Settings → USB.
- Make sure Enable USB Controller is checked. Choose USB 2.0 (EHCI) or USB 3.0 (xHCI) depending on your host and token. The xHCI controller requires the VirtualBox Extension Pack.
- Click the Add USB filter icon (plug with a green plus). Insert the FIDO token into the host first so it appears in the device list, then select it. This creates a filter that automatically routes that token to the VM whenever it is inserted.
- Click OK and start the VM.
- Once booted, insert the FIDO token and verify the guest sees it:
Normal user shell
lsusb fido2-token -Lfido2-token -Lshould list a device path such as/dev/hidraw1: vendor model FIDO+U2F. If it returns nothing, confirm the USB filter is saved and the correct controller type is selected.
5. Install required packages
Uses sudosudo apt update
sudo apt install libpam-u2f pamu2fcfg fido2-tools pamtester
1.
pam_u2f PIN support — the floor is 1.1.1, not 1.1.0. This guide uses pinverification=1 (section 9). PIN verification arrived in libpam-u2f 1.1.0 — but 1.1.0 shipped a PIN-authentication bypass, CVE-2021-31924, fixed in 1.1.1 (2021-05-19). On 1.1.0 the very control this lab teaches can be bypassed, so treat 1.1.1 as the real minimum. Mint 22 is comfortably current. Mint 21 ships 1.1.1 — fixed, but exactly on the boundary — so confirm before relying on it:
dpkg -l libpam-u2f | tail -n1If the version is older than 1.1.1, do not use this lab to demonstrate PIN enforcement: enable
backports or upgrade to Mint 22. (Older than 1.1.0 and pinverification is not merely weak — it is unknown to the module, so it is ignored or errors.)
2.
common-auth shape. The Ubuntu-base /etc/pam.d/common-auth differs slightly from Debian's, but this guide never edits common-auth directly — it inserts @include fido2-local-auth above the existing @include common-auth line in each service (sections 12, 13), so the strategy holds on both bases.6. Set or verify the FIDO2 PIN
Normal user shellfido2-token -L
Example output:
/dev/hidraw1: KEY-ID FIDO+U2F
Normal user shell
fido2-token -I /dev/hidraw1
Set a PIN if needed:
Normal user shellfido2-token -S /dev/hidraw1
Change an existing PIN if needed:
Normal user shellfido2-token -C /dev/hidraw1
fido-token-test.sh, that detects a key, dumps its identity, and runs a live touch/crypto round-trip before you enroll it. Ask your instructor to vet a new token first — the tool and its safe reset/identity features live in the Instructor Reference, not this walkthrough.7. Pre-PAM FIDO2/PIN test
Before touching PAM, verify that the token accepts its PIN and requires physical presence.
Normal user shellrm -rf /tmp/fido2-login-test
mkdir -p /tmp/fido2-login-test
cd /tmp/fido2-login-test
Normal user shell
echo "debian local login test challenge" | openssl sha256 -binary | base64 > cred_param
echo "localhost" >> cred_param
echo FIDO_USER >> cred_param
dd if=/dev/urandom bs=32 count=1 status=none | base64 >> cred_param
Normal user shell
fido2-cred -M -t pin=true -i cred_param /dev/hidraw1 | fido2-cred -V -o cred
Expected behavior for a KEY-ID FIDO+U2F style token: enter the FIDO2 PIN, watch for the LED/button to flash, then press the token button. The command should return successfully and create cred.
ls -l cred
cat cred
If you intentionally enter a bad PIN, FIDO_ERR_PIN_INVALID is expected. If you run without -t pin=true and see FIDO_ERR_PIN_REQUIRED, rerun with -t pin=true.
cd
rm -rf /tmp/fido2-login-test
8. Create and populate the FIDO login group
The fido-login group is the selector. Members use FIDO2; non-members use password auth.
sudo groupadd --force fido-login
sudo usermod -aG fido-login FIDO_USER
id FIDO_USER
getent group fido-login
9. Create the central PAM mapping file
Use a central mapping file instead of ~/.config/Yubico/u2f_keys. This avoids encrypted-home and graphical-locker timing problems.
pamu2fcfg -N -u FIDO_USER > /tmp/u2f_keys-FIDO_USER
cat /tmp/u2f_keys-FIDO_USER
Expected: token PIN prompt, optional flashing/touch, and one mapping line beginning with FIDO_USER:.
sudo install -o root -g fido-login -m 0640 /tmp/u2f_keys-FIDO_USER /etc/security/u2f_keys
rm -f /tmp/u2f_keys-FIDO_USER
sudo python3 -c 'from pathlib import Path; p=Path("/etc/security/u2f_keys"); p.write_text(p.read_text().rstrip()+"\n")'
sudo ls -l /etc/security/u2f_keys
sudo grep "^FIDO_USER:" /etc/security/u2f_keys
Expected permissions:
-rw-r----- 1 root fido-login ... /etc/security/u2f_keys
0640 root:fido-login? Some graphical unlockers run PAM in the user’s session context, not as root. A root-only 0600 mapping file can work under sudo pamtester but fail during actual screen unlock. The mapping file contains public credential registration data, not the token private key, so group-readable by fido-login is appropriate for this design.Enroll a backup token
Insert the backup token, then append a second credential to the same user line.
Uses sudo and normal user commandssudo cp /etc/security/u2f_keys /tmp/u2f_keys-FIDO_USER.new
sudo chown FIDO_USER:fido-login /tmp/u2f_keys-FIDO_USER.new
chmod 0640 /tmp/u2f_keys-FIDO_USER.new
printf ':' >> /tmp/u2f_keys-FIDO_USER.new
pamu2fcfg -N -n >> /tmp/u2f_keys-FIDO_USER.new
sudo install -o root -g fido-login -m 0640 /tmp/u2f_keys-FIDO_USER.new /etc/security/u2f_keys
rm -f /tmp/u2f_keys-FIDO_USER.new
sudo python3 -c 'from pathlib import Path; p=Path("/etc/security/u2f_keys"); p.write_text(p.read_text().rstrip()+"\n")'
sudo ls -l /etc/security/u2f_keys
10. Create a shared PAM include file
Instead of copying the same FIDO logic into every PAM service, put it in one reusable include file.
success=done. Use PAM include/@include, not substack, so successful FIDO authentication stops before password auth.sudo test -e /etc/pam.d/fido2-local-auth && sudo cp -a /etc/pam.d/fido2-local-auth /etc/pam.d/fido2-local-auth.bak || true
sudo tee /etc/pam.d/fido2-local-auth >/dev/null <<'EOF'
{{EMBED:config/fido2-local-auth}}
EOF
Use one of these include styles depending on the surrounding PAM file:
Debian/Ubuntu @include style@include fido2-local-auth
@include common-auth
Typed auth include styleauth include fido2-local-auth
auth include common-auth
11. Test PAM with a standalone service
Create a temporary PAM service before editing LightDM, sudo, su, or screen-locker files.
Backup if file exists, then write test servicesudo test -e /etc/pam.d/fido2-test && sudo cp -a /etc/pam.d/fido2-test /etc/pam.d/fido2-test.bak || true
sudo tee /etc/pam.d/fido2-test >/dev/null <<'EOF'
{{EMBED:config/fido2-test}}
EOF
Uses sudosudo pamtester fido2-test FIDO_USER authenticate
sudo pamtester fido2-test BREAKGLASS_USER authenticate
Expected: FIDO_USER gets FIDO PIN + touch only. BREAKGLASS_USER gets password only.
If pamtester says “Authentication service cannot retrieve authentication info”
Diagnostic commandswhoami
id FIDO_USER
getent group fido-login
sudo ls -l /etc/security/u2f_keys
sudo grep "^FIDO_USER:" /etc/security/u2f_keys
sudo cat /etc/pam.d/fido2-local-auth
sudo cat /etc/pam.d/fido2-test
12. Configure LightDM graphical login
slick-greeter (lightdm-slick-greeter) as the LightDM greeter, whereas the Debian XFCE lab this guide is derived from used lightdm-gtk-greeter. The PAM file you edit is the same — /etc/pam.d/lightdm — and the group-gated policy behaves identically. What differs is only how the greeter renders the FIDO PIN prompt and cue. The prompt-quirk guidance later in this section is written for Slick Greeter but has not been validated on Mint; confirm the actual on-screen behavior on your install. Check which greeter is active with:
cat /etc/lightdm/lightdm.conf.d/*.conf /etc/lightdm/lightdm.conf 2>/dev/null | grep -i greeter-sessionEdit /etc/pam.d/lightdm, not /etc/pam.d/lightdm-greeter, for normal user login authentication.
sudo cp -a /etc/pam.d/lightdm /etc/pam.d/lightdm.bak
sudo editor /etc/pam.d/lightdm
Find the service’s existing password include, usually:
@include common-auth
Insert the shared FIDO include immediately above it. Preserve unrelated lines such as pam_nologin, pam_env, SELinux, limits, loginuid, and keyring lines.
# FIDO2 local authentication policy
@include fido2-local-auth
@include common-auth
Do not modify lightdm-greeter on the first pass
/etc/pam.d/lightdm-greeter normally permits the greeter process itself to start. It is not the normal user-authentication path.
auth required pam_permit.so
Optional: prefer username-first graphical login
The group-gated PAM design needs to know the username before it selects the FIDO or password path. LightDM supports manual username entry when the greeter supports it. The greeter-hide-users and greeter-show-manual-login settings below are LightDM seat settings, honored by Slick Greeter as well as the GTK greeter.
sudo mkdir -p /etc/lightdm/lightdm.conf.d
sudo tee /etc/lightdm/lightdm.conf.d/50-manual-login.conf >/dev/null <<'EOF'
{{EMBED:config/50-manual-login.conf}}
EOF
Expected presentation:
Username:
Password/PIN:
greeter-show-manual-login=true to take effect only after a full LightDM restart (sudo systemctl restart lightdm — do this only from a safe recovery position, not mid-configuration).Pre-logout LightDM PAM test
Uses sudosudo pamtester lightdm FIDO_USER authenticate
sudo pamtester lightdm BREAKGLASS_USER authenticate
Slick Greeter prompt behavior
Verify on your install — not yet validated on Mint. On the GTK greeter (Debian XFCE), the greeter sometimes displays blank prompt lines for the FIDO/PAM conversation until Enter is pressed. Slick Greeter renders the PAM conversation differently, and its handling of a custom pam_u2f cue and PIN prompt has not been confirmed for this lab. When you test the greeter on Mint, note exactly what appears: whether the PIN prompt and the cue text (“FIDO users: enter token PIN, then touch token when it flashes”) are shown, whether you must press Enter first, and whether the token flashes on schedule. Record the observed flow so it can be documented for students.
13. Configure sudo
Backup, then editsudo cp -a /etc/pam.d/sudo /etc/pam.d/sudo.bak
sudo editor /etc/pam.d/sudo
Place the shared FIDO include immediately before @include common-auth.
session required pam_limits.so
@include fido2-local-auth
@include common-auth
@include common-account
@include common-session-noninteractive
Testsudo -k
sudo -v
sudo package owns /etc/pam.d/sudo as a dpkg conffile. Unattended or non-interactive upgrades — including unattended-upgrades, automated patching, or accepting a "replace modified conffile" prompt at an apt prompt — can silently replace your edited file with the package default, removing @include fido2-local-auth and disabling FIDO for sudo with no warning. Complete section 13.1 before proceeding.13.1 Protect the sudo PAM configuration from package updates
Install an apt post-invoke hook that checks for the FIDO include after every apt invocation and re-adds it if a package upgrade removed it.
Step 1: Create the guard script.
Uses sudosudo tee /usr/local/sbin/fido2-sudo-pam-guard >/dev/null <<'EOF'
{{EMBED:scripts/fido2-sudo-pam-guard}}
EOF
sudo chmod 755 /usr/local/sbin/fido2-sudo-pam-guard
Step 2: Install the apt hook.
Uses sudosudo tee /etc/apt/apt.conf.d/99-fido2-sudo-pam-guard >/dev/null <<'EOF'
{{EMBED:config/99-fido2-sudo-pam-guard}}
EOF
Step 3: Verify the guard works before relying on it.
Test# Confirm the include is present
sudo grep fido2-local-auth /etc/pam.d/sudo
# Simulate removal, run the guard, confirm it re-adds the line
sudo sed -i '/fido2-local-auth/d' /etc/pam.d/sudo
sudo /usr/local/sbin/fido2-sudo-pam-guard
sudo grep fido2-local-auth /etc/pam.d/sudo
# Confirm sudo still requires FIDO
sudo -k
sudo -v
@include fido2-local-auth is present in /etc/pam.d/sudo. If a package upgrade removed it, the script re-inserts it immediately before @include common-auth and logs the event via logger. The hook is a no-op when the include is already present. Trade-off: if a future sudo upgrade restructures the file and removes @include common-auth as the marker, the re-insertion will silently fail — check /var/log/syslog for fido2-sudo-pam-guard entries after major upgrades.sudo using your password (the FIDO include is gone but common-auth falls back to password). Re-run the guard manually — sudo /usr/local/sbin/fido2-sudo-pam-guard — then confirm with sudo -k && sudo -v that FIDO is active again.passwd -l. If a package upgrade removes the FIDO include and the password is locked, common-auth has nothing to fall back to — the FIDO user cannot run sudo at all. Your only recovery path is the password-only breakglass account. This is exactly why the breakglass account must remain password-capable, must stay outside the fido-login group, and must never have its password locked.14. Core FIDO login checkpoint
At this point, the core FIDO login design is complete only if the standalone PAM test, LightDM test, breakglass test, and real sudo -v test all pass.
| Core test | Command or action | Expected result |
|---|---|---|
| FIDO test service | sudo pamtester fido2-test FIDO_USER authenticate | FIDO PIN + touch only. |
| Breakglass test service | sudo pamtester fido2-test BREAKGLASS_USER authenticate | Password only. |
| LightDM FIDO user | sudo pamtester lightdm FIDO_USER authenticate | FIDO PIN + touch only. |
| LightDM breakglass user | sudo pamtester lightdm BREAKGLASS_USER authenticate | Password only. |
| Real sudo from FIDO session | sudo -k, then sudo -v | FIDO PIN + touch from the actual FIDO_USER session. |
The remaining sections are desktop-integration and hardening steps: optional su, required greeter-based lock behavior, token-removal greeter switching, password locking, keyring behavior, and rollback.
15. Configure su, optional
This is optional. Preserve pam_rootok.so before the FIDO include so root-originated su keeps normal behavior.
sudo cp -a /etc/pam.d/su /etc/pam.d/su.bak
sudo editor /etc/pam.d/su
The important ordering is:
PAM snippetauth sufficient pam_rootok.so
@include fido2-local-auth
@include common-auth
Testsu - FIDO_USER
su - BREAKGLASS_USER
16. Configure MATE lock behavior: use the LightDM greeter, not the raw screen locker
gsettings keybinding paths and the idle settings — must be confirmed on your actual Mint MATE VM.The in-process mate-screensaver unlock dialog is not a good primary FIDO unlock surface: like the XFCE screensaver, it authenticates only the currently logged-in user, does not offer Switch User, and can flicker or loop when the token is absent. The design used here sends the user to the LightDM greeter for lock instead, which preserves Switch User and the password-only breakglass account.
mate-screensaver unlock dialog as the normal FIDO unlock path. Use the LightDM greeter for manual lock, switch-user behavior, and token-removal locking (section 17). Keep mate-screensaver PAM-valid only as an idle-timeout fallback.Keep the MATE screensaver PAM file sane as a fallback
Even though the primary lock flow uses the LightDM greeter, keep /etc/pam.d/mate-screensaver valid. This prevents confusing PAM errors if MATE still invokes the screensaver dialog during idle timeout or other edge cases.
sudo cp -a /etc/pam.d/mate-screensaver /etc/pam.d/mate-screensaver.bak.before-fido2-local-auth
sudo editor /etc/pam.d/mate-screensaver
Use this content:
PAM snippet#%PAM-1.0
auth include fido2-local-auth
auth include common-auth
auth optional pam_gnome_keyring.so
account required pam_permit.so
The explicit account required pam_permit.so line avoids the pam_unix(...:account): setuid failed account-management problem observed with the analogous XFCE screensaver service.
Test the PAM service directly:
Uses sudosudo pamtester mate-screensaver FIDO_USER authenticate
sudo pamtester mate-screensaver FIDO_USER acct_mgmt
sudo pamtester mate-screensaver BREAKGLASS_USER authenticate
sudo pamtester mate-screensaver BREAKGLASS_USER acct_mgmt
| Test | Expected result |
|---|---|
FIDO_USER authenticate | FIDO PIN + touch. |
FIDO_USER acct_mgmt | Success. |
BREAKGLASS_USER authenticate | Password. |
BREAKGLASS_USER acct_mgmt | Success. |
Make manual lock switch to the LightDM greeter
MATE has no xflock4-style indirection. Its lock shortcut (by default Ctrl+Alt+L) invokes mate-screensaver directly through the mate-settings-daemon media-keys plugin. To route lock to the greeter instead, clear the built-in lock shortcut and add a MATE custom keybinding that runs dm-tool switch-to-greeter. Run these as FIDO_USER inside the graphical MATE session — these are per-user gsettings, not sudo.
# 1. Clear MATE's built-in "lock screen" shortcut (a single-string key) so it
# no longer launches mate-screensaver directly.
gsettings set org.mate.settings-daemon.plugins.media-keys screensaver ''
# 2. Define one custom shortcut. MATE's media-keys plugin enumerates children
# of /org/mate/desktop/keybindings/, each using the relocatable schema
# org.mate.control-center.keybinding with keys name / action / binding.
BASE="org.mate.control-center.keybinding:/org/mate/desktop/keybindings/custom0/"
gsettings set "$BASE" name "'Lock to LightDM greeter'"
gsettings set "$BASE" action "'dm-tool switch-to-greeter'"
gsettings set "$BASE" binding "'<Mod4>l'"
<Mod4>l is Super+L; use <Control><Alt>l if you prefer to keep the familiar Ctrl+Alt+L. Do not bind it to the same accelerator you just cleared unless you have confirmed the built-in is really gone, or the two will fight.Verify the settings were written:
Normal graphical session (as FIDO_USER)gsettings get org.mate.settings-daemon.plugins.media-keys screensaver
gsettings get "$BASE" action
gsettings get "$BASE" binding
Test manual locking by pressing your chosen shortcut, or by running the command the keybinding invokes directly from the session terminal:
Normal graphical session (as FIDO_USER)dm-tool switch-to-greeter
Expected behavior:
- The machine switches to the LightDM greeter instead of the
mate-screensaverunlock dialog. - The FIDO user authenticates through LightDM with FIDO PIN + touch.
- The breakglass user remains available with normal password authentication.
- Switch-user behavior remains available at the greeter.
custom0 shortcut — you may need to log out and back in for a newly-added custom keybinding to be picked up — and (b) the built-in shortcut no longer also triggers mate-screensaver. If lock still raises the native locker, re-check that org.mate.settings-daemon.plugins.media-keys screensaver is empty.If dm-tool switch-to-greeter fails from a terminal
The greeter switch needs the graphical session environment: DISPLAY, XDG_RUNTIME_DIR, and DBUS_SESSION_BUS_ADDRESS. A nested login shell such as su - FIDO_USER may strip those variables.
echo "$DISPLAY"
echo "$XDG_RUNTIME_DIR"
echo "$DBUS_SESSION_BUS_ADDRESS"
If these are empty, exit the nested login shell and test from the original MATE terminal session. (The token-removal helper in section 17 does not have this limitation — it reconstructs the session environment from loginctl.)
Idle-timeout locking on MATE
MATE cannot run an arbitrary command on idle the way a configurable locker can, so there is no clean way to make idle timeout switch to the greeter. You must choose one of two idle postures, and test the one you pick before considering the setup complete:
- Disable native idle locking and rely on manual lock (your shortcut → greeter) and token removal (section 17) as the lock triggers. The screen may still blank on idle, but it will not auto-lock — acceptable only where physical access is otherwise controlled.
Normal graphical session (as FIDO_USER)
gsettings set org.mate.screensaver lock-enabled false gsettings set org.mate.screensaver idle-activation-enabled false gsettings set org.mate.session idle-delay 0 - Keep native idle locking via
mate-screensaver, accepting that an idle lock lands on the in-process FIDO unlock dialog (which you kept PAM-valid above) rather than the greeter. The FIDO PIN + touch flow still works, but Switch User and breakglass are not available from that dialog until the token is reinserted.
Check which lockers are running:
Normal graphical sessionpgrep -a 'mate-screensaver|light-locker|xscreensaver|xsecurelock'
17. Switch to the LightDM greeter when the FIDO key is removed
This section sends the machine to the LightDM greeter when the FIDO token is removed. It depends on the greeter-based lock behavior configured and tested in the previous section. This is part of the intended desktop behavior for this FIDO-only setup, but it is still not an authentication control; the real authentication control remains the FIDO/PAM login policy.
mate-screensaver-command --lock or forcing the mate-screensaver unlock dialog. The greeter path preserves access to user switching and the password-only breakglass account. The helper and udev rule below are the DE-agnostic pieces reused verbatim from the XFCE lab; they were tested there, but the end-to-end token-removal flow has not yet been validated on Mint MATE — confirm it on your install.mate-screensaver-command --lock? Locking into the in-process mate-screensaver dialog on token removal can trap the user inside the current session's FIDO-only unlock dialog. If the token is absent, the unlock dialog may flicker or repeatedly restart, and the Switch User path may not be available until the token is reinserted. Switching to the LightDM greeter avoids that failure mode.17.1. Confirm the greeter switch command exists
Normal graphical sessioncommand -v dm-tool
Expected result:
Example output/usr/bin/dm-tool
From the real MATE terminal session, test switching to the greeter:
Normal graphical sessiondm-tool switch-to-greeter
Expected behavior: the session switches to the LightDM greeter. From there, the FIDO user should be able to authenticate with FIDO PIN + touch, and the breakglass user should be able to authenticate with a normal password.
17.2. Find the token's udev identifiers
Insert the FIDO key, then monitor udev events:
Uses sudosudo udevadm monitor --udev --environment
Remove the FIDO key and look for the hidraw remove event. Prefer the event that includes ID_FIDO_TOKEN=1 and ID_SECURITY_TOKEN=1.
ACTION=remove
SUBSYSTEM=hidraw
DEVNAME=/dev/hidraw1
ID_FIDO_TOKEN=1
ID_SECURITY_TOKEN=1
ID_VENDOR_ID=096e
ID_MODEL_ID=0858
ID_MODEL=FIDO
Record ID_VENDOR_ID and ID_MODEL_ID. If your token exposes a truly unique serial number, you may also match on that, but some tokens expose a generic product serial string rather than a per-token serial.
17.3. Create the greeter-switch helper
This helper is run by root through udev/systemd, finds the active local graphical session, reconstructs the session environment, and runs dm-tool switch-to-greeter as the graphical user.
sudo tee /usr/local/sbin/fido-remove-switch-to-greeter >/dev/null <<'EOF'
{{EMBED:scripts/fido-remove-switch-to-greeter}}
EOF
sudo chown root:root /usr/local/sbin/fido-remove-switch-to-greeter
sudo chmod 0755 /usr/local/sbin/fido-remove-switch-to-greeter
17.4. Test the helper manually
Uses sudosudo /usr/local/sbin/fido-remove-switch-to-greeter
Expected behavior: the session switches to the LightDM greeter. After returning, inspect logs:
Troubleshootingsudo journalctl -b --since "3 minutes ago" | grep -Ei 'fido-switch-greeter|dm-tool|lightdm|greeter'
If dm-tool reports Not running inside a display manager, XDG_SEAT_PATH not defined, verify that the helper includes the XDG_SEAT_PATH=/org/freedesktop/DisplayManager/Seat0 environment variable.
17.5. Test a logging-only udev rule first
Before letting udev switch the greeter, confirm the rule fires on the correct remove event. Replace the vendor/model IDs with the values observed from your token.
Uses sudosudo tee /etc/udev/rules.d/85-fido-lock-on-remove-test.rules >/dev/null <<'EOF'
{{EMBED:config/85-fido-lock-on-remove-test.rules}}
EOF
sudo udevadm control --reload-rules
Remove the token, then check for the test log:
Troubleshootingsudo journalctl -b --since "2 minutes ago" | grep -i fido-udev-test
If the test log appears, remove the test rule:
Uses sudosudo rm -f /etc/udev/rules.d/85-fido-lock-on-remove-test.rules
sudo udevadm control --reload-rules
17.6. Create the real udev removal rule
Do not run dm-tool directly from udev. udev jobs should be short-lived. Use systemd-run --no-block to hand the work off to systemd.
sudo tee /etc/udev/rules.d/85-fido-lock-on-remove.rules >/dev/null <<'EOF'
{{EMBED:config/85-fido-lock-on-remove.rules}}
EOF
sudo udevadm control --reload-rules
17.7. Test token removal
- Stay logged into MATE.
- Insert the FIDO key.
- Remove the FIDO key.
- The machine should switch to the LightDM greeter.
- Select the FIDO user and reinsert the token to authenticate with FIDO PIN + touch, or select the password-only breakglass user.
Check logs after the test:
Troubleshootingsudo journalctl -b --since "3 minutes ago" | grep -Ei 'fido-switch-greeter|fido-udev|udev|dm-tool|lightdm|greeter'
17.8. Notes on testing the greeter switch by hand
Running dm-tool switch-to-greeter by hand only works from the original graphical MATE session environment. It needs DISPLAY, XDG_RUNTIME_DIR, and DBUS_SESSION_BUS_ADDRESS. If those variables are empty, such as inside a nested su - login shell, the manual command may fail even though the desktop session is healthy.
echo "$DISPLAY"
echo "$XDG_RUNTIME_DIR"
echo "$DBUS_SESSION_BUS_ADDRESS"
The greeter-switch helper does not depend on the current shell environment; it reconstructs the graphical session environment from loginctl.
17.9. Rollback the removal-switch feature (optional)
sudo rm -f /etc/udev/rules.d/85-fido-lock-on-remove.rules
sudo rm -f /etc/udev/rules.d/85-fido-lock-on-remove-test.rules
sudo rm -f /usr/local/sbin/fido-remove-switch-to-greeter
sudo udevadm control --reload-rules
18. Extended test matrix before reboot
| Test | Command or action | Expected result |
|---|---|---|
| FIDO test service | sudo pamtester fido2-test FIDO_USER authenticate | FIDO PIN + touch only. |
| Breakglass test service | sudo pamtester fido2-test BREAKGLASS_USER authenticate | Password only. |
| LightDM FIDO user | sudo pamtester lightdm FIDO_USER authenticate | FIDO PIN + touch only. |
| LightDM breakglass user | sudo pamtester lightdm BREAKGLASS_USER authenticate | Password only. |
| Real sudo from FIDO session | sudo -k, then sudo -v | FIDO behavior for the actual FIDO_USER session. |
su, if configured | su - FIDO_USER and su - BREAKGLASS_USER | Correct path per account. If su includes fido2-local-auth, su - FIDO_USER may succeed by FIDO instead of password. |
| Manual lock | Press Super+L (or run dm-tool switch-to-greeter) | Switches to the LightDM greeter. FIDO user authenticates through LightDM with PIN + touch; breakglass user remains available. |
| Idle-timeout lock | Wait for the configured idle timeout (posture chosen in section 16). | Per your chosen idle posture: either no auto-lock (native idle disabled) or the native mate-screensaver FIDO dialog. No flicker loop. Breakglass reachable via the greeter after a manual Super+L. |
| FIDO key removal | Remove the FIDO token from an active graphical session. | System switches to the LightDM greeter. User switching and breakglass login remain available. |
- §12 greeter: Slick Greeter shows a usable FIDO PIN prompt (and the manual-username field, if enabled).
- §16 manual lock: Super+L switches to the LightDM greeter; the built-in
mate-screensavershortcut no longer fires. - §16 idle: your chosen idle posture behaves as expected (no auto-lock, or native locker with FIDO PAM).
- §16 fallback PAM:
pamtester mate-screensaver FIDO_USER authenticatepasses. - §17 removal: pulling the token switches to the greeter; check
ID_VENDOR_ID/ID_MODEL_IDmatch your token and thatID_FIDO_TOKEN=1is set on the remove event.
Reboot only after tests pass
Uses sudosudo reboot
19. Disable Unix password login for FIDO users
After the FIDO login path, LightDM greeter lock behavior, sudo behavior, breakglass account, and recovery path have been fully tested, the FIDO-enabled user can be made token-only by locking that user's Unix password. This prevents password-based authentication for that user while keeping the account itself valid for normal login, group membership, sudo policy, and PAM account/session checks.
BREAKGLASS_USER with a known-working password. Do not lock the breakglass account's password.passwd -l FIDO_USER, console TTY password recovery for that user is no longer available. Your password-based recovery path is BREAKGLASS_USER.Lock the password, not the account. Use passwd -l for the FIDO user. Do not expire the account, disable the shell, delete the user, or remove normal group memberships.
sudo passwd -l FIDO_USER
Verify the password state:
Uses sudosudo passwd -S FIDO_USER
sudo getent shadow FIDO_USER
The shadow password field should begin with !, indicating that password authentication is locked for that account. The account should still exist and should still be a member of fido-login.
Verify group membership:
Normal user shellid FIDO_USER
getent group fido-login
Retest after locking the password
Run the core tests again before logging out or rebooting. Prefer operational tests from the actual FIDO_USER graphical session over synthetic-only tests.
sudo -k
sudo -v
# then press Super+L (or run: dm-tool switch-to-greeter)
Uses sudo
sudo pamtester lightdm FIDO_USER authenticate
sudo pamtester lightdm BREAKGLASS_USER authenticate
sudo pamtester mate-screensaver FIDO_USER authenticate
| Test | Expected result |
|---|---|
FIDO_USER through LightDM | FIDO PIN + touch only. |
FIDO_USER through real sudo -v | FIDO PIN + touch only. |
| Manual lock (Super+L) | Switches to the LightDM greeter, then FIDO PIN + touch through LightDM. |
BREAKGLASS_USER through LightDM | Password only. |
Confirm the Unix password itself is locked
If su has been modified to include fido2-local-auth, then su - FIDO_USER may still succeed through FIDO. That is expected. To prove that the Unix password itself is locked, test a password-only path such as an unmodified TTY login for FIDO_USER, or perform this check before enabling FIDO for su.
FIDO-protected PAM services should continue to work because fido2-local-auth exits successfully before falling through to common-auth.
Restore password login later, if needed
Uses sudosudo passwd -u FIDO_USER
Only unlock the password if you intentionally want password-based authentication restored for that account.
20. Optional: GNOME Keyring and Chrome/Chromium prompts
After converting a user to FIDO-only login, Chrome or Chromium may ask for the GNOME Keyring password when it tries to access stored browser secrets. This is expected.
login keyring using the password entered during login. In the FIDO-only flow, the user authenticates with token PIN + touch, so there is no Unix password for pam_gnome_keyring.so to reuse.This means FIDO2 can authenticate the desktop login, but it does not automatically decrypt an existing password-protected keyring. The keyring password remains separate.
20.1. Options
| Option | Behavior | Tradeoff |
|---|---|---|
| Keep the keyring password | Chrome/Chromium prompts for the keyring password when needed | Most conservative; preserves separate protection for keyring secrets |
| Set the login keyring password blank | Chrome/Chromium stops prompting for the keyring password | Convenient, but keyring secrets are no longer protected by a separate keyring password after session start |
| Restore password login | GNOME Keyring may auto-unlock from the login password | Undermines the FIDO-only account goal |
20.2. Install Seahorse
The graphical keyring editor may not already be installed. Install Seahorse:
Uses sudosudo apt install seahorse
apt nonetheless reports dependency errors, try the following:
sudo apt install --fix-brokensudo apt update && sudo apt full-upgradeIf dependencies still cannot be resolved, an alternative is to manage the keyring password from the command line using
secret-tool (from the libsecret-tools package) or by deleting and recreating the keyring file at ~/.local/share/keyrings/login.keyring. Note that deleting the keyring file will erase all stored keyring secrets.Launch it:
Normal graphical sessionseahorse
20.3. Set the login keyring password blank
- Open Passwords and Keys / Seahorse.
- Find the Login keyring.
- Right-click the Login keyring and choose Change Password.
- Enter the current keyring password.
- Leave the new password fields blank.
- Accept the warning about storing passwords unencrypted, if this matches your threat model.
After this, Chrome/Chromium should stop asking for the keyring password when launched inside the FIDO-only user session.
20.4. Do not automate this step
This walkthrough treats blanking the keyring password as an explicit user choice. Do not automate it in the PAM migration script, because it changes how local application secrets are protected.
21. Emergency rollback
If a PAM change breaks authentication and you still have a root-capable shell, remove the shared include references first:
Uses sudosudo sed -i '/fido2-local-auth/d' /etc/pam.d/lightdm /etc/pam.d/sudo /etc/pam.d/su /etc/pam.d/mate-screensaver 2>/dev/null || true
sudo rm -f /etc/pam.d/fido2-local-auth
sudo rm -f /etc/lightdm/lightdm.conf.d/50-manual-login.conf
sudo rm -f /etc/udev/rules.d/85-fido-lock-on-remove.rules
sudo rm -f /etc/udev/rules.d/85-fido-lock-on-remove-test.rules
sudo rm -f /usr/local/sbin/fido-remove-switch-to-greeter
sudo rm -f /usr/local/sbin/lock-on-fido-remove
sudo udevadm control --reload-rules
If you need to restore backed-up PAM files:
Uses sudosudo test -e /etc/pam.d/lightdm.bak && sudo cp -a /etc/pam.d/lightdm.bak /etc/pam.d/lightdm || true
sudo test -e /etc/pam.d/sudo.bak && sudo cp -a /etc/pam.d/sudo.bak /etc/pam.d/sudo || true
sudo test -e /etc/pam.d/su.bak && sudo cp -a /etc/pam.d/su.bak /etc/pam.d/su || true
sudo test -e /etc/pam.d/mate-screensaver.bak.before-fido2-local-auth && sudo cp -a /etc/pam.d/mate-screensaver.bak.before-fido2-local-auth /etc/pam.d/mate-screensaver || true
sudo test -e /etc/pam.d/mate-screensaver.bak && sudo cp -a /etc/pam.d/mate-screensaver.bak /etc/pam.d/mate-screensaver || true
gsettings, not a root-owned file, so it is not touched by the rollback above. To restore MATE's default lock shortcut, run as FIDO_USER: gsettings reset org.mate.settings-daemon.plugins.media-keys screensaver and remove the custom0 shortcut under /org/mate/desktop/keybindings/.Restart display manager only when ready
Uses sudosudo systemctl restart lightdm
If you are locked out entirely, boot recovery or a live USB, mount the system, and remove the fido2-local-auth includes from the PAM files.
22. Option notes and policy choices
Common pam_u2f options used here
| Option | Meaning |
|---|---|
authfile=/etc/security/u2f_keys | Use the central root-managed mapping file. |
cue | Ask PAM/greeter to show a human cue when the token is waiting for a touch. Graphical greeters may display it imperfectly. Note cue="..." is not valid — PAM has no shell quoting; a custom message needs the bracket form [cue_prompt=your text here], whose availability on Mint 21's 1.1.1 is unverified (section 5). |
pinverification=1 | Require the FIDO2 token PIN during authentication. |
userverification=0 | Do not require a separate biometric or authenticator-level user-verification feature. The expected flow here is token PIN plus physical presence/touch. |
pinverification=1 requires the token PIN. userverification=0 avoids requiring a separate biometric or authenticator-level UV feature. This is appropriate for KEY-ID FIDO+U2F style behavior where the desired flow is PIN + flashing-button touch.pamu2fcfg options used here
| Option | Meaning |
|---|---|
-N | Enroll a credential that requires PIN verification. |
-u FIDO_USER | Create the mapping line for that user. |
-n | Output only credential data so a backup token can be appended. |
Why edit selected PAM services?
This guide edits LightDM, sudo, optional su, and the actual screen-locker PAM file. It does not edit common-auth globally, because a mistake there can break too many authentication paths at once.
Lock policy used here
This guide uses the LightDM greeter as the normal lock/unlock surface for FIDO users. The raw mate-screensaver unlock dialog is kept PAM-valid as an idle-timeout fallback, but it is not the preferred primary unlock UI for FIDO-only use.
23. References and source notes
- Packages (Debian/Ubuntu/Mint):
libpam-u2f,pamu2fcfg,fido2-tools, andpamtester. - MATE settings schemas:
org.mate.settings-daemon.plugins.media-keys,org.mate.control-center.keybinding,org.mate.screensaver, andorg.mate.session(viagsettings). - Yubico
pam_u2fmanual: documentsauthfile,cue,pinverification,userverification,nouserok, and passwordless examples. - Yubico
pamu2fcfgmanual: documents-Nand-n. - libfido2
fido2-tokenandfido2-credmanuals: document listing tokens, setting/changing PINs, and make-credential tests with-t pin=true. pam_succeed_ifmanual: documents group-based selection withuser ingroup.- LightDM common configuration and sample config: document
greeter-hide-usersandgreeter-show-manual-login. loginctlmanual: documentslock-sessions.dm-toolmanual: documentsswitch-to-greeterand the LightDM seat environment it requires.- udev documentation: covers matching USB device add/remove events with udev rules; systemd's
fido_idbuiltin setsID_FIDO_TOKEN.