A remembered-device token with no absolute expiry survives a password reset — what has your second factor become, and what fixes it?
answer
- convenience is not authority
- measure the clock from issue
- re-issue copies the deadline forward
- credential change deletes every row
- skips the routine prompt, nothing else
basics
~20 sIt has become a permanent bearer credential — anyone holding that value signs in with a password alone, forever. Fix it with an absolute lifetime measured from issue, and deletion of every device record when the account's credentials change.
solid answer
~50 sTwo controls have failed at once. Without an absolute expiry the record never ends for a machine in regular use, so a value that leaks keeps skipping the second factor indefinitely; and by surviving a password reset it makes the reset cosmetic, because the reset was the account holder's way of saying *something has gone wrong, cut everything off*. The fix is an `absolute_expires_at` fixed at issue and never recomputed — if you re-issue the value on each use, copy the original deadline forward rather than restarting it — plus deleting every remembered-device row for the account on a password change or reset, a second-factor re-enrolment, and any explicit "this wasn't me" report. And keep the grant narrow: the record skips the routine second-factor prompt on an ordinary sign-in and satisfies no demand for fresh proof of the person.
code
pseudocode · 20 lineson sign_in(account, password, device_cookie):
require password_ok(account, password) # first factor, always
record = find_device_record(account, hash(device_cookie))
if record is null:
return CHALLENGE
if now >= record.absolute_expires_at:
delete(record)
return CHALLENGE
# value rotation only: the deadline is copied, never recomputed
new_value = random_256_bits()
record.token_hash = hash(new_value)
record.last_used_at = now
save(record)
set_cookie(new_value, expires = record.absolute_expires_at)
return SKIP_SECOND_FACTOR
on credentials_changed(account): # reset, change, re-enrolment
delete_all_device_records(account)go deeper
Remember that a remembered-device record must have an end date fixed when it is issued, and that changing or resetting the account's password gets rid of every one of those records.
Explain why re-issuing the value on each use has to copy the original deadline rather than compute a new one, and why an expiry that slides forward never ends for a device in regular use.
Price the lifetime out loud: prompts saved per record against how long a leaked value keeps working. Name the load-bearing control — the absolute ceiling — and say what is left standing once it is removed.
The judgment call is what the skip may cover at all. Argue that it buys back one routine prompt and nothing else, and that widening it to satisfy fresh-proof demands is how a convenience quietly becomes an authorisation.
## The clock the record must run on A remembered-device record has exactly one clock that matters: an **absolute lifetime measured from the moment it was issued**. Write `absolute_expires_at` when the row is created, derive it from `issued_at`, and treat it as immutable for the life of that row. Everything else about the record — how often it is used, whether the value was re-issued, what the member is doing — leaves that deadline alone. The alternative that ships by accident is an expiry pushed forward on every use. It is a natural thing to write and it is the defect in the question: a device in weekly use is then trusted **for as long as the member keeps using it**, which is to say indefinitely. The control looks present in the code and is absent in effect. There is exactly one legitimate way the window moves: the old row is deleted and a **new record is issued**, with a new `issued_at` and a new deadline — and issuing a new record is a decision the server makes deliberately, usually behind a fresh second-factor proof, not a side effect of a successful sign-in. ## Re-issue on use, without extending anything Re-issuing the random value each time the record is used is a reasonable thing to do: it limits how long any single value has been sitting in one place. But it is a *value* rotation, not a *record* rotation. The row keeps its `issued_at` and its `absolute_expires_at`; only `token_hash` and `last_used_at` change, and the cookie that carries the new value must still be set to expire no later than the original deadline. Get this backwards and the re-issue becomes exactly the sliding expiry you were trying to avoid, wearing a more careful name. ## The grant is narrow, and the narrowness is the design The second thing a long-lived record gives away is scope, and this one is worth stating as a rule: | The record may | The record may not | |---|---| | Skip the routine second-factor prompt on an ordinary sign-in | Stand in as fresh proof for an operation that demands it | | Be presented alongside the first factor, never instead of it | Replace the password on any path | | Exist while the account holder is signed out | Confer any authority of its own once signed in | The reason is the same one that governs the binding: possession of a machine is not evidence about the person in front of it. A record that can satisfy a fresh-proof demand has converted a convenience into an authorisation, and the borrowed tablet in the association's shed now speaks for whichever plot-holder last used it. ## The events that must delete every row Some events are statements about the account's credentials, and every one of them must delete **all** remembered-device rows for that account, not just the one in front of you: 1. **A password change or reset.** Especially a reset: the member is usually telling you something went wrong. A reset that leaves ten devices skipping the second factor has changed almost nothing for the person who already has the old password and one of those devices. 2. **A second-factor enrolment change** — a new authenticator registered, an old one removed. The records were issued against a factor configuration that no longer exists. 3. **An explicit report from the member** ("this wasn't me", "I lost the tablet"). Deleting all rows is the cheap, correct answer; asking them to identify which one is not. Note what is *not* on this list: signing out. Sign-out ends a session and leaves the standing statement about the machine intact, which is the behaviour the member asked for when they ticked the box. ## Pricing the lifetime A senior answer prices the number rather than quoting one. The lifetime buys back prompts: roughly one avoided challenge per sign-in per remembered machine, for as long as the record lives. It costs you a window in which a leaked value signs in with a password alone. So the lifetime is short where the account can act on other people — the association's committee members who edit the plot register or the waiting list — and can be longer where it cannot. The load-bearing control is the **absolute ceiling**. Remove it and everything else still works: the row is still bound to one account and one browser, the value is still hashed at rest, the grant is still narrow — and the account still has one factor in practice for every machine it has ever trusted. Remove the deletion-on-credential-change rule instead and you keep the ceiling, but you lose the only lever the member has to end it early. Those two, together, are what make remembering a device a bounded trade rather than a permanent one.
- How would you choose the absolute lifetime for an allotment association's plot-holder accounts?Price it rather than pick it. Count the prompts a record avoids over its life and set that against how long a leaked value would keep signing in with a password alone. Ordinary plot-holders, who can only see their own plot and the rota, tolerate a longer window; committee accounts that edit the plot register or the waiting list get a short one, because the cost side of the trade is much larger there.
- A member asks why they are being challenged again when they already ticked "do not ask again".Because the tick covered one thing: the routine second-factor prompt on an ordinary sign-in. Anything that demands fresh proof of the person is a different demand, and holding the tablet answers none of it. The honest explanation to give the member is that the machine is remembered, not them — and that the record also has an end date, so it will ask again eventually whatever they do.
- Should signing out delete the remembered-device record?No. Sign-out ends a session; the record is a standing statement that this browser may skip a prompt on a future sign-in, and surviving sign-out is exactly what the member asked for. Deleting it there would make the feature pointless. Deletion belongs to credential events — a password change or reset, a factor re-enrolment, an explicit report from the member — and to the absolute deadline.
A season ticket at the gate, not a signature on a form. The attendant who waves through whoever carries the ticket is right to — the ticket buys the gate, and that is all it was sold to buy. He is wrong the moment someone asks him to witness a signature with it: the ticket proves a ticket turned up, never who is holding it. And a season ticket carries a printed end date precisely because nobody can remember who still has one.
saying these in an interview costs you the question
- Pushing the expiry forward on every use, so an active device never ages out.
- Accepting a remembered device as the fresh proof a sensitive action demands.
- Leaving device records alive after a password reset, so the reset changes little.
- Choosing the lifetime by what members will tolerate rather than what it grants.
- Treating a stolen device value as harmless because the password is still needed.
- Deleting only the record in front of you when a credential changes.