How I added another layer of verification to make account sharing and proxy attendance harder.
The Problem
In my previous article, I explained how I used dynamic QR authentication to reduce one of the simplest forms of proxy attendance:
screenshot and share the QR code.
But that introduced another question.
What if the student shares their account instead?
Consider this scenario:
Classroom
Student A
│
└── Has valid account + trusted device
Hostel
Student B
│
└── Gets Student A's credentials
│
└── Logs in from another phone
│
└── Attempts attendance
The QR code can be valid.
The credentials can be valid.
The user can be authenticated.
And the attendance request can still be illegitimate.
So I needed another verification layer.
Authentication Isn't the Same as Device Trust
Traditional authentication primarily answers:
Who is this user?
For this attendance system, I also wanted to answer:
Is this request coming from the device associated with this account?
That led me to implement device-bound authentication.
The idea is straightforward:
User Account
│
▼
Trusted Device
│
▼
Attendance Request
│
▼
Backend Verification
The device becomes another signal that the backend can use when deciding whether an attendance request should continue.
The Device Registration Flow
At a high level, the flow looks like this:
First Login
│
▼
Generate / Retrieve Device Identifier
│
▼
Associate Device With Account
│
▼
Store Device Association
│
▼
Future Requests
│
▼
Backend Compares Device Identity
│
├── Match ────────► Continue
│
└── Mismatch ─────► Reject
The important part is that the final decision happens on the backend.
The client shouldn't be able to simply say:
"Trust me, this is my device."
The backend needs to validate the request against the device association it already knows about.
The 1-to-1 Device Lock
In my implementation, the relevant student flow uses a strict one-to-one device association.
The repository uses the persistent identifier:
uba_emergency_device_id
to maintain that device association.
Conceptually:
Student A
│
└── Device A ✅
But:
Student A
│
├── Device A ✅
│
└── Device B ❌
The important distinction is that having valid credentials doesn't automatically make a new device trusted.
Where Device Verification Fits
Device binding doesn't replace dynamic QR authentication.
It adds another layer to it.
The attendance request becomes something closer to:
Attendance Request
│
▼
User Authentication
│
▼
Dynamic QR Validation
│
▼
Device Verification
│
▼
Backend Validation
│
▼
Attendance Recorded
Each layer addresses a different problem.
Dynamic QR
Makes previously captured QR codes much less useful.
Authentication
Establishes the student's account identity.
Device verification
Makes casual account sharing across devices harder.
Backend validation
Keeps the final decision on the server.
Why Not Just Trust the Client?
This is an important principle I learned while building the system:
The client should provide information. The backend should decide whether that information can be trusted.
A device identifier coming from the browser isn't magically secure.
A determined attacker may be able to manipulate client-side identifiers depending on the environment.
That's why I don't treat device binding as an unbreakable security mechanism.
It's another signal.
The goal is not:
"Make proxy attendance impossible."
The goal is:
"Make casual proxy attendance significantly harder without making legitimate attendance painful."
The Recovery Problem
Device binding immediately creates another problem.
What happens when the legitimate user changes devices?
Phones get:
- Lost
- Replaced
- Reset
- Repaired
- Reconfigured
Browser storage can also disappear.
A security mechanism without recovery can become worse than the problem it was designed to solve.
So a real implementation has to consider:
Trusted Device
│
├── Device lost
├── New phone
├── Storage reset
└── Device replacement
│
▼
Recovery Process
This is one of the areas where authentication becomes a system-design problem rather than just an if statement.
Security vs Usability
Every additional security layer introduces friction.
More checks can mean:
More security
but also:
More ways to accidentally block legitimate users.
For this project, I think about the trade-off as:
Security
×
Usability
×
Recoverability
All three matter.
A system that blocks every suspicious request but also locks legitimate students out isn't a good attendance system.
Likewise, a system that is extremely convenient but accepts every request isn't doing much to prevent proxy attendance.
What This Doesn't Protect Against
It's important not to oversell device binding.
It can help reduce:
- Basic account sharing
- Casual multi-device access
- Credential-based proxy attendance
- Repeated use of one student's account from another device
But it doesn't automatically prevent:
- Sophisticated attackers
- Compromised devices
- Manipulation of client-side identifiers
- Someone physically using the registered device
Security is about the threat model.
For my project, I'm primarily trying to prevent ordinary proxy attendance, not defend against a nation-state with a lab full of reverse engineers.
The Bigger Lesson
When I started this project, I thought proxy attendance was mainly a QR-code problem.
It wasn't.
It became an identity problem.
The QR tells the system about the attendance session.
Authentication tells it about the student.
Device verification provides another signal about the device making the request.
Backend validation brings those signals together.
That led me to a broader lesson:
Security rarely comes from one perfect mechanism. It comes from multiple layers that compensate for each other's weaknesses.
What's Next?
Device-bound authentication solved another part of the proxy-attendance problem.
But it also introduced more engineering questions.
How should these validations interact with the database?
How do you minimize Firestore reads while performing multiple checks?
How should suspicious device changes be logged?
And how do you design the backend so that adding security doesn't make every attendance request unnecessarily expensive?
Those are the problems I'm exploring as I continue building the system.
Final Thoughts
I started with a simple question:
"How do I stop someone from sharing a QR code?"
Then it became:
"What stops them from sharing an account?"
And eventually:
"How do I know the request is coming from a trusted device?"
That's been one of the most interesting parts of building this project.
The architecture wasn't designed perfectly on day one.
It evolved as each new problem exposed another weakness.
And honestly, that's probably the most realistic way to build software.
Project
🔗 GitHub: https://github.com/siddarthpatelkama/UBA-veltech-attendance-system
💼 LinkedIn: https://www.linkedin.com/in/siddarthpatelkama
Top comments (0)