TapAuth is my Raspberry Pi NFC attendance and reservation system for the Asia Pacific College School of Engineering AIRHub.
I started this as a straightforward tap-in and tap-out kiosk. Then I thought about what happens when the internet drops, MySQL restarts, or a newly registered card is tapped again immediately. That changed the project: the Pi now recognizes cards from its own durable registry first, keeps normal kiosk interactions fast, and reconciles data with MySQL and Firebase when those services are available.
- Detects whether a registered NFC card should check in or check out.
- Lets an unknown card register through a short, tap-bound session.
- Keeps registered cards recognizable without depending on MySQL for every tap.
- Supports 3D printing requests and teacher appointments.
- Shows the latest 25 activity records, with a compact See more view.
- Provides a private student and reservation management page.
- Mirrors safe activity data to Firebase without exposing NFC identifiers.
- Runs without a frontend build step: Flask, Python, HTML, CSS, and JavaScript.
Oh! On card registration, saving a student once is not enough if the next lookup depends entirely on a database connection. TapAuth stores a private copy at data/registered_cards.json on the Pi. The write is atomic, a backup is kept, and the directory is ignored by Git.
The tap flow is:
NFC card
|
v
Local card registry ---- recognized immediately
|
+---- MySQL available? ---- sync student and attendance data
|
+---- Firebase available? - copy approved private/public records
MySQL remains the main operational database. The local registry is the recognition fallback, not a public student database. Firebase is an optional remote copy and public-safe activity source.
The browser preview uses simulated taps and local browser storage:
python -m http.server 4173Open http://127.0.0.1:4173.
For the real NFC flow, run the Flask application on a Raspberry Pi with an ACR122U reader.
You need Raspberry Pi OS, an ACR122U USB NFC reader, and internet access for the first installation. Firebase is optional.
git clone https://github.com/devkyato/TapAuth.git
cd TapAuth
cp .env.example .env
nano .env
bash scripts/setup_raspberry_pi.shThe setup script installs MariaDB, Python dependencies, libnfc, reader permissions, the airhub.service systemd unit, and Chromium kiosk startup.
After setup:
- Kiosk:
http://127.0.0.1:5000/ - Student management:
http://127.0.0.1:5000/admin - System status:
http://127.0.0.1:5000/system_status
Copy .env.example to .env. At minimum, replace these values:
AIRHUB_DB_USER=airhub_app
AIRHUB_DB_PASSWORD=replace-with-a-strong-password
AIRHUB_DB_NAME=airhub_db
TAPAUTH_ADMIN_CODE=replace-with-a-private-admin-codeTAPAUTH_REGISTRY_PATH may be left blank to use data/registered_cards.json.
To enable Firebase:
AIRHUB_FIREBASE_ENABLED=true
AIRHUB_FIREBASE_MODE=realtime_db
AIRHUB_FIREBASE_DATABASE_URL=https://your-project-default-rtdb.region.firebasedatabase.app
AIRHUB_FIREBASE_DATABASE_SECRET=your-server-side-database-secret
AIRHUB_FIREBASE_PROJECT_ID=your-project-id
AIRHUB_FIREBASE_ROOT=tapauthThe Firebase browser apiKey identifies the web app; it is not an administrator secret. Never commit .env, database secrets, service-account files, student records, or NFC UIDs.
I treated Firebase as a synchronized view, not as a requirement for tapping a card. This keeps the kiosk usable on the local network even when cloud access is interrupted.
npm install -g firebase-tools
firebase login --no-localhost
firebase use your-project-id
firebase deploy --only database,hostingTo copy existing MySQL records:
source .venv/bin/activate
python scripts/sync_realtime_db.pyPrivate users and reservations live below tapauth/users and tapauth/reservations. Only sanitized event and timing fields under tapauth/logs are publicly readable.
cd ~/TapAuth
git pull --ff-only origin main
bash scripts/update_pi_from_github.sh
sudo systemctl restart airhub.service
sudo systemctl status airhub.serviceThe update script also reconciles MySQL students with the local card registry. If MySQL is temporarily unavailable, the existing local registry stays usable.
bash scripts/diagnose_nfc.sh
sudo systemctl restart airhub.service
journalctl -u airhub.service -fTapAuth retries disconnected readers automatically. The setup disables pcscd because it can claim the ACR122U before libnfc.
| Path | Purpose |
|---|---|
app.py |
Flask API, tap sessions, registration, attendance, and admin routes |
scanner.py |
ACR122U reader loop and reconnection |
nfc_utils.py |
Stable UID normalization |
local_registry.py |
Durable card-recognition fallback |
database.py |
MySQL students, logs, reservations, and sync queue |
firebase_adapter.py |
Firebase Realtime Database writer |
index.html, script.js |
Kiosk and reservation interface |
templates/admin.html |
Local management page |
hosting/ |
Firebase-hosted public activity page |
scripts/ |
Setup, update, sync, diagnostics, backup, and migration |
tests/ |
Registration, privacy, UID, registry, and activity tests |
For a deeper technical reference, see ARCHITECTURE.md.
python -m compileall -q .
node --check script.js
node --check hosting/app.js
node --check hosting/firebase-config.js
python -m json.tool firebase.json
python -m json.tool database.rules.json
python -m unittest discover -s tests -vThis is a personal project, but focused issues and pull requests are welcome. Please read CONTRIBUTING.md, use SUPPORT.md for diagnostics, and report security problems privately through SECURITY.md.
TapAuth is available under the MIT License.
