amir 093ddb7fce security: move signing key out of source (rotated), add local replay guard
- Remove committed release keystore + hardcoded signing password
- Load signing config from gitignored app/keystore.properties
- Add single-use token guard (fail-open) to block on-device approval replay
2026-07-10 09:31:13 +00:00

Homelab MFA

Biometric push-approval for your homelab logins. When you sign in through Authentik, your phone buzzes — approve with a fingerprint, or deny with one tap. A self-hosted alternative to Duo / Authy push, with no third-party cloud in the loop.

How it works

  1. You log in via Authentik. A flow step fires an ntfy notification to your phone with two action buttons: Approve and Deny.
  2. The buttons are homemfa://approve?token=… / homemfa://deny?token=… deep links that open this app.
  3. Approve opens an in-app review screen showing who is asking (see context params below), then triggers a biometric prompt (fingerprint / face / device PIN). On success the app POSTs approve:<token> to ntfy.khodak.me/mfa-approve; your Authentik flow is listening on that topic and completes the login. You can also Deny right from that screen.
  4. Deny POSTs deny:<token> to mfa-deny and blocks the login — no biometric needed to reject.

Optional context params

The approve link may carry extra query params so you can see what you're approving before you do:

Param Shown as Example
app 🖥 application name app=Grafana
user 👤 username user=amir
ip 📍 source IP ip=203.0.113.44
geo appended to the IP geo=Berlin, DE
ts request timestamp (epoch ms) — used to expire stale prompts after 2 min ts=1750000000000

All are optional and URL-encoded; with none present the app just shows a plain Approve / Deny prompt.

The activity is showWhenLocked + turnScreenOn, so an approval works straight from the lock screen.

Features

  • Biometric gateBIOMETRIC_STRONG or device credential required to approve (deny is instant)
  • Login context — see the app, user, source IP and geo of the request before approving
  • One-tap Deny — reject a suspicious login straight from the approval screen, no biometric needed
  • Stale-request expiry — prompts older than 2 minutes can't be approved (replay safety net)
  • Lock-screen ready — wakes the screen and shows over the keyguard
  • Self-hosted — talks only to your own ntfy instance; no Firebase, no vendor cloud
  • Zero stored secrets — stateless; each request carries a one-time token
  • Setup self-check — a "Test Biometric" button confirms enrollment before you rely on it

Screenshots

Setup / ready screen   Approval prompt with login context   Login approved

Install

  1. Download homelab-mfa.apk from the latest release
  2. On your Android phone: Settings → Apps → Install unknown apps → allow your browser/file manager
  3. Open the APK and tap Install
  4. Open Homelab MFA and tap Test Biometric to confirm your fingerprint is enrolled

Server side

You need:

  • An ntfy instance reachable at ntfy.khodak.me (or change the host in MainActivity.kt)
  • An Authentik flow that, on login, publishes a notification with the two homemfa:// action buttons, then waits on the mfa-approve / mfa-deny topics for the decision

Requirements

  • Android 9.0+ (API 28)
  • A fingerprint, face, or device PIN enrolled
S
Description
Android biometric approval gate for Authentik logins via ntfy push — tap Approve, confirm with fingerprint.
Readme
61 MiB
v1.3
Latest
2026-07-10 10:03:00 +00:00
Languages
Kotlin 86.4%
Shell 13.6%