goauthentik / goauthentik/authentik
Limit number of MFA devices per user (cap and/or auto-expire stale devices)
- Dominant language
- Python
- Stars
- 25.6k
- Forks
- 2k
- Avg merge
- 1d 2h
- Merged PRs (30d)
- 659
Description
### Is your feature request related to a problem?
There is currently no way to limit how many MFA devices a user can enroll. Over time users accumulate authenticators (old phones, replaced security keys, stale TOTP entries) that are never cleaned up. This creates two concerns:
- **Security/hygiene:** abandoned-but-still-valid devices increase the attack surface and make it harder to reason about which credentials are trusted.
- **Administration:** admins have no policy lever to enforce an organizational limit (e.g. "at most 2 TOTP + 2 WebAuthn per user").
Today the only related controls are partial: the Email authenticator is hardcoded to one device per user, and the WebAuthn stage has `prevent_duplicate_devices` and `max_attempts` — but none of these cap the total device count or expire aging devices.
### Describe the solution you'd like
Open to either (or both) of these approaches and would like community/maintainer input on preference:
1. **Maximum device count parameter** — a configurable cap on the number of enrolled devices, enforced at enrollment time. Ideally configurable per authenticator enrollment stage (and/or per device class), with `0`/unset meaning unlimited, consistent with existing fields like WebAuthn `max_attempts`.
2. **Auto-expire stale devices** — automatically remove (or mark unusable) MFA devices that have not been used within a configurable age/threshold, similar in spirit to the Authenticator Validate stage's `last_auth_threshold`. This naturally bounds the number of *active* devices without a hard cap.
### Describe alternatives that you've considered
- **Expression Policy bound to the enrollment stage** that counts `Device.objects.devices_for_user(user)` and denies enrollment past a threshold. This works today but is per-deployment custom logic, isn't discoverable, and can't easily auto-clean stale devices.
- **Manual admin cleanup** of old devices — not scalable and error-prone.
### Additional context
- Email authenticator one-device limit: `authentik/stages/authenticator_email/stage.py`
- WebAuthn `prevent_duplicate_devices` / `max_attempts`: `authentik/stages/authenticator_webauthn/models.py`
- `last_auth_threshold` precedent for time-based behavior: `authentik/stages/authenticator_validate/models.py`
Question for the community: is a hard **device-count cap** preferred, an **auto-expire by age** mechanism, or both?
Contributor guide
Research direction
Start by comparing authentik/stages/authenticator_email/stage.py, authentik/stages/authenticator_webauthn/models.py, and authentik/stages/authenticator_validate/models.py for the existing device-limit and threshold precedents. Clarify with maintainers whether the desired outcome is a count cap, stale-device expiry, or both; done requires an agreed policy and acceptance criteria before implementation.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- python
- Domain
- authentication, security
- Issue type
- Feature
- Difficulty
- 5/5
- Estimated time
- Over a week
- Activity status
- Quiet
- Clarity
- Needs clarification
- Newbie friendliness
- 32/100