Table of Contents
- Why Two Factor Authentication for Physical Locks?
- How RFID + Fingerprint 2FA Works
- Components Required
- Wiring the Circuit
- Enrolling Fingerprints
- Main 2FA Lock Code
- Adding OLED Display Feedback
- Security Hardening Tips
- Real-World Use Cases in India
- FAQs
Why Two Factor Authentication for Physical Locks?
Two factor authentication (2FA) is a standard practice in digital security: you need something you have (a token or card) AND something you are (biometric) to gain access. Most physical locks use only one factor — a key (something you have), a PIN (something you know), or a fingerprint (something you are). A two-factor lock combines two of these, meaning an intruder who steals your RFID card cannot enter without your fingerprint, and someone who forcibly obtains your fingerprint still cannot enter without the card.
Building a 2FA lock with RFID and fingerprint sensors is now an accessible DIY project. The MFRC522 RFID reader costs about ₹150, the R307 fingerprint sensor costs around ₹450, and an Arduino Uno or ESP32 costs ₹300–₹450. Total build cost is under ₹2,000 — a fraction of commercial biometric locks that often cost ₹6,000–₹15,000.
This guide covers the complete build: wiring, fingerprint enrollment, main 2FA code, OLED display integration, and practical deployment tips for offices, server rooms, and home entryways across India.
How RFID + Fingerprint 2FA Works
The authentication flow is sequential:
- Step 1 — RFID: User presents their RFID card or fob. The MFRC522 reader reads the card UID. The microcontroller checks it against a list of authorised UIDs.
- Step 2 — Fingerprint: Only if RFID passes, the system prompts for a fingerprint scan. The R307 sensor captures the fingerprint, converts it to a template, and searches its onboard memory for a match.
- Access granted: Only if BOTH factors authenticate successfully within a timeout window (15–30 seconds) does the door unlock.
- Failure handling: If either factor fails, the entire sequence resets. The user must start again with the RFID card — there is no way to skip step 1 and go directly to fingerprint.
This architecture ensures defence-in-depth. Even a sophisticated attacker who clones your RFID card (using a Proxmark or similar tool) still cannot enter without your enrolled fingerprint. Conversely, lifted fingerprint copies (extremely difficult) are useless without the physical card.
Components Required
| Component | Notes | Approx. Cost (₹) |
|---|---|---|
| Arduino Uno R3 | Main controller; Nano works too | 300–450 |
| MFRC522 RFID Reader | Comes with card + key fob | 130–200 |
| R307 Fingerprint Sensor | UART interface, stores 162 templates | 400–550 |
| 12V DC Solenoid Lock | Normally-locked (NL) type | 250–400 |
| 5V Relay Module | To switch 12V solenoid from Arduino | 40–80 |
| OLED 0.96″ I2C Display | Status and feedback messages | 150–250 |
| Active Buzzer (5V) | Audio feedback on pass/fail | 20–40 |
| LEDs (Red + Green) | Visual indicators | 10–20 |
| 12V 2A Power Supply | For solenoid; 5V from Arduino regulator | 150–250 |
Wiring the Circuit
The MFRC522 uses SPI communication; the R307 fingerprint sensor uses UART (serial). Both can run simultaneously on Arduino.
MFRC522 RFID (SPI):
- SDA → D10 (SS_PIN)
- SCK → D13
- MOSI → D11
- MISO → D12
- RST → D9
- 3.3V → Arduino 3.3V pin
- GND → GND
R307 Fingerprint Sensor (UART via SoftwareSerial):
- TX (sensor) → D2 (Arduino RX)
- RX (sensor) → D3 (Arduino TX)
- VCC → 5V (some R307 modules need 3.3V — check your module spec)
- GND → GND
Solenoid Lock via Relay:
- Relay IN → D7
- Relay VCC → 5V, GND → GND
- Relay COM → 12V+, NO → Solenoid+, Solenoid- → 12V GND
- Add a 1N4007 flyback diode across the solenoid terminals to protect the relay from inductive spikes
Enrolling Fingerprints
Before running the main 2FA code, you must enrol each authorised user’s fingerprint into the R307 sensor’s onboard memory. The R307 stores up to 162 unique fingerprint templates internally, so no additional storage is needed.
// Fingerprint Enrollment Sketch
// Run this once to add fingerprints, then switch to main 2FA code
void enrollFingerprint(int id) {
Serial.println("Enrolling ID #" + String(id));
Serial.println("Place finger on sensor...");
while (finger.getImage() != FINGERPRINT_OK);
if (finger.image2Tz(1) != FINGERPRINT_OK) { Serial.println("Error"); return; }
Serial.println("Remove finger");
delay(2000);
Serial.println("Place same finger again...");
while (finger.getImage() != FINGERPRINT_OK);
if (finger.image2Tz(2) != FINGERPRINT_OK) { Serial.println("Error"); return; }
if (finger.createModel() != FINGERPRINT_OK) { Serial.println("Mismatch"); return; }
if (finger.storeModel(id) == FINGERPRINT_OK) {
Serial.println("Fingerprint stored at ID #" + String(id));
}
}
Upload this enrollment sketch, open Serial Monitor at 9600 baud, and follow the prompts. Each user is assigned an ID number (1, 2, 3…). Record which ID belongs to which person — you will need this for the access log.
For RFID, record each card’s UID by scanning it and reading the Serial output. Add each authorised UID to the validUIDs[] array in the main code.
Main 2FA Lock Code
// 2FA Lock: RFID + Fingerprint
// Both must authenticate for access
#include <SPI.h>
#include <MFRC522.h>
#include <Adafruit_Fingerprint.h>
#include <SoftwareSerial.h>
// RFID pins (SPI)
#define SS_PIN 10
#define RST_PIN 9
MFRC522 rfid(SS_PIN, RST_PIN);
// Fingerprint sensor (UART)
SoftwareSerial fpSerial(2, 3); // RX, TX
Adafruit_Fingerprint finger(&fpSerial);
// Door lock
#define LOCK_PIN 7
#define BUZZER_PIN 6
#define GREEN_LED 5
#define RED_LED 4
// Authorised RFID UIDs (stored as hex strings)
String validUIDs[] = {"A1B2C3D4", "11223344"};
int numUIDs = 2;
bool rfidPassed = false;
String currentUID = "";
void setup() {
Serial.begin(9600);
SPI.begin();
rfid.PCD_Init();
fpSerial.begin(57600);
finger.begin(57600);
pinMode(LOCK_PIN, OUTPUT);
pinMode(BUZZER_PIN, OUTPUT);
pinMode(GREEN_LED, OUTPUT);
pinMode(RED_LED, OUTPUT);
lockDoor();
Serial.println("2FA Lock Ready - Present RFID card");
}
void loop() {
if (!rfidPassed) {
checkRFID();
} else {
Serial.println("RFID OK - Now scan fingerprint");
checkFingerprint();
}
}
void checkRFID() {
if (!rfid.PICC_IsNewCardPresent() || !rfid.PICC_ReadCardSerial()) return;
String uid = "";
for (byte i = 0; i < rfid.uid.size; i++) {
if (rfid.uid.uidByte[i] < 0x10) uid += "0";
uid += String(rfid.uid.uidByte[i], HEX);
}
uid.toUpperCase();
bool found = false;
for (int i = 0; i < numUIDs; i++) {
if (uid == validUIDs[i]) { found = true; break; }
}
if (found) {
rfidPassed = true;
currentUID = uid;
indicateSuccess();
Serial.println("RFID Auth: " + uid);
} else {
indicateFailure();
Serial.println("RFID Denied: " + uid);
}
rfid.PICC_HaltA();
}
void checkFingerprint() {
int result = finger.getImage();
if (result != FINGERPRINT_OK) return;
result = finger.image2Tz();
if (result != FINGERPRINT_OK) { rfidPassed = false; return; }
result = finger.fingerSearch();
if (result == FINGERPRINT_OK) {
Serial.println("FP Auth: ID #" + String(finger.fingerID));
unlockDoor();
delay(5000); // Keep unlocked 5 seconds
lockDoor();
rfidPassed = false;
} else {
indicateFailure();
rfidPassed = false; // Reset - must retry RFID too
Serial.println("FP Denied");
}
}
void unlockDoor() {
digitalWrite(LOCK_PIN, HIGH); // Energise solenoid
digitalWrite(GREEN_LED, HIGH);
tone(BUZZER_PIN, 1000, 200);
}
void lockDoor() {
digitalWrite(LOCK_PIN, LOW);
digitalWrite(GREEN_LED, LOW);
digitalWrite(RED_LED, HIGH);
delay(100);
digitalWrite(RED_LED, LOW);
}
void indicateSuccess() {
digitalWrite(GREEN_LED, HIGH);
tone(BUZZER_PIN, 1500, 100);
delay(200);
digitalWrite(GREEN_LED, LOW);
}
void indicateFailure() {
for (int i = 0; i < 3; i++) {
digitalWrite(RED_LED, HIGH);
tone(BUZZER_PIN, 400, 150);
delay(200);
digitalWrite(RED_LED, LOW);
delay(100);
}
}
Key implementation details:
- Sequential authentication: The
rfidPassedboolean flag gates fingerprint checking. Fingerprint code only runs after RFID has been verified. - Automatic timeout: Add a 30-second timeout to reset
rfidPassedif the user presents the RFID card but does not scan their fingerprint in time. This prevents leaving the system in a partially-authenticated state. - Fail-reset: Any fingerprint failure resets
rfidPassed = false, requiring the user to restart with the RFID card. - Solenoid control: The relay drives the 12V solenoid. HIGH signal = door unlocked; LOW = locked. A normally-locked solenoid is safer: power loss = door stays locked.
Adding OLED Display Feedback
The OLED display significantly improves the user experience by showing clear instructions at each step. Install the Adafruit SSD1306 and Adafruit GFX libraries via Arduino Library Manager.
Replace the Serial.println calls with OLED display commands:
- Idle state: “Present RFID Card”
- After RFID pass: “Card OK – Scan Finger”
- After fingerprint pass: “Access Granted – Welcome [Name]”
- On failure: “Access Denied” with a countdown to retry
To show the user’s name on the OLED, create a lookup array mapping fingerprint IDs to names: String userNames[] = {"Admin", "Ravi Kumar", "Priya"}. When fingerprint ID 2 matches, display “Welcome Ravi Kumar”.
Security Hardening Tips
A DIY lock can be made significantly more secure with these additional measures:
- Anti-tamper enclosure: Mount all electronics inside a metal enclosure behind the door or wall panel. If the enclosure is opened, trigger an alarm using a magnetic reed switch or microswitch wired to an interrupt pin.
- RFID UID randomisation: Basic RFID cards have static UIDs that can be cloned easily. Use MIFARE 1K cards with DESFire encryption or roll-code RFID for higher security. For most home/office use, static UID is acceptable if combined with fingerprint.
- Wrong attempt lockout: After 3 consecutive failed attempts (RFID or fingerprint), lock the system for 5 minutes and send an SMS alert. Add this logic using a counter variable.
- Access logging: Log every access event (UID, fingerprint ID, timestamp) to an SD card or via GSM/Wi-Fi to a Google Sheet. This provides an audit trail for offices and server rooms.
- Backup access: In case of sensor failure, add a hidden numeric keypad as a tertiary backup. This should use a different PIN than any other system and be physically concealed.
Real-World Use Cases in India
Small office server room: IT managers use 2FA locks to ensure only authorised engineers can access network equipment. The access log answers “who entered the server room and when” for audit compliance.
Pharmacy dispensary cabinet: Controlled substances require dual authorisation in many Indian pharmacy regulations. An RFID card (pharmacist) plus fingerprint (same person) ensures no single person can access medications alone.
Residential main gate: Pairs with a 12V electric strike lock on a metal gate. The RFID card for family members + fingerprint prevents a stolen card from being used. Works perfectly with Indian 230V power supply — 12V derived from an adapter.
Jewellery shop locker room: High-value storage areas in jewellery shops require multi-person authorisation. Extend the code to require two different people’s RFID + fingerprint before unlocking (manager + owner).
School lab equipment room: Teachers use RFID cards; fingerprint confirms identity. Prevents student card sharing. Capacity of 162 fingerprints accommodates an entire school staff.
Frequently Asked Questions
Can I use ESP32 instead of Arduino for this project?
Yes, ESP32 is a better choice if you want Wi-Fi connectivity to log access events remotely or receive app notifications. The MFRC522 and R307 libraries work with ESP32. Use hardware UART (UART2 on pins 16/17) for the fingerprint sensor instead of SoftwareSerial for more reliable high-speed communication.
How many RFID cards and fingerprints can I store?
RFID UIDs are stored in Arduino program memory (flash) as strings. You can store hundreds within the available 32KB flash space. The R307 fingerprint sensor stores up to 162 templates onboard. If you need more, use the AS608 module which stores up to 200 templates.
What if the fingerprint sensor fails to read due to dry skin or humidity?
Indian summers cause dry skin, and monsoon humidity causes wet fingers — both affect fingerprint read accuracy. Enrol multiple fingerprints per person (both index fingers, at ID 1 and ID 2). In the code, check if either ID matches. Also increase the sensor’s security level parameter using finger.setSecurityLevel(3) (out of 5) for a balance between security and acceptance rate.
Can this lock survive outdoor installation?
The MFRC522 and R307 are not waterproofed. For outdoor installation, mount the readers inside a weatherproof enclosure with only the card reader face and fingerprint window exposed. Use automotive-grade silicone sealant around any openings. The R307 fingerprint window should be covered with a sliding panel to protect from rain when not in use.
How do I remove a user from the system?
For RFID, remove the UID from the validUIDs[] array and re-upload the sketch. For fingerprints, use finger.deleteModel(id) to erase a specific template from the R307 sensor. This can be triggered remotely via serial command or a dedicated admin keypress sequence.
What is the power consumption and can it run on battery?
In idle mode, the system draws about 100–150mA. When the solenoid is energised, it draws 400–800mA additionally. A 12V 7Ah SLA battery provides approximately 6–8 hours of backup (assuming the door opens 20 times per day with 5-second unlock each). For longer backup, use a 12V 20Ah battery with a mains charger.
Add comment