A risk service answers allow, challenge or deny on each sign-in — what must your authentication path do with each answer?
answer
- three outcomes, plus one for silence
- allow is not skip
- verdict first, then the device record
- silence is named, not an exception
- authentication owns the default
basics
~20 sMap each answer to a sign-in outcome: allow continues the ordinary path, challenge demands a second factor, deny ends the attempt with a recorded reason. Silence is a fourth named outcome, defaulting to the challenge.
solid answer
~50 sWrite the contract from the authentication side, because the sign-in path is the component that has to act. **Allow** does not mean *skip a factor* — it means the ordinary path continues, and only then is a remembered-device record consulted. **Challenge** means demand the second factor regardless of any remembered device. **Deny** ends the attempt, records why, and must not be overridable by a known machine. The fourth case is the one designs forget: **no answer arrived in time**. Treat it as a named outcome with a written default rather than whatever the timeout path happens to do, and default it to the challenge — the middle outcome exists precisely so this is not a binary between letting everyone in and locking everyone out. That default is a policy about who gets in, so it belongs to whoever owns authentication.
code
pseudocode · 23 lineson sign_in(account, password, device_cookie, request):
require password_ok(account, password)
verdict = risk_service.ask(account, request) # may return nothing
if verdict == DENY:
record_outcome(account, "refused: risk-deny")
return REFUSE_WITH_ROUTE_BACK
if verdict == CHALLENGE:
record_outcome(account, "challenged: risk-challenge")
return DEMAND_SECOND_FACTOR
if verdict is MISSING: # the named fourth outcome
record_outcome(account, "challenged: no-verdict")
return DEMAND_SECOND_FACTOR
# verdict == ALLOW: ordinary path, and only here does the device record count
if live_device_record(account, hash(device_cookie)):
record_outcome(account, "signed in: device-skip")
return SIGN_IN_COMPLETE
record_outcome(account, "challenged: no-device-record")
return DEMAND_SECOND_FACTORgo deeper
Recall that a sign-in risk answer has three outcomes, not two: allow, challenge and deny. Allow means the ordinary sign-in continues, not that a factor gets skipped.
Explain the ordering: the verdict is consulted before the remembered-device record, so a deny cannot be overridden by a known machine. Say what the member sees in each of the three cases.
Show that silence is handled as a named fourth outcome with a written default, and that the sign-in path records which branch it took, so a denial spike and a silence spike can be told apart at three in the morning.
This is an ownership question. The default for a missing answer is a policy about who gets into accounts, so it belongs to whoever owns authentication rather than to whoever operates the service that went quiet — and it must be written and exercised before it is needed.
## Three outcomes, and they are genuinely three A sign-in risk verdict is usually drawn as a gate: open or shut. That framing is the source of most of the trouble, because the useful shape has three outcomes and the middle one carries the design. | Verdict | What the sign-in path does | What the member experiences | |---|---|---| | **allow** | Continue the ordinary sign-in path — *then* consult the remembered-device record | Signs in; may or may not be prompted, depending on the record | | **challenge** | Demand the second factor, ignoring any remembered-device record | Prompted, even on a machine they ticked "do not ask again" on | | **deny** | End the attempt, record the reason, offer a route back | Refused, with something actionable to do next | The first row is where candidates slip. **Allow is not a skip.** It means nothing was seen that warrants extra friction, so the normal rules apply — and the normal rules include asking for the second factor unless a live remembered-device record says otherwise. A design that reads allow as "let them straight in" has quietly deleted the second factor for every sign-in the service considered unremarkable, which is nearly all of them. ## Ordering: the verdict, then the device record The remembered-device record is an **input to the ordinary path, not an override of the verdict**, and that means the verdict is consulted first. Put the device lookup first and a deny becomes unreachable for exactly the machines an attacker is most likely to be holding — the ones already trusted. The order the sign-in path must impose is: 1. Verify the first factor. Nothing in this contract touches that. 2. Ask for a verdict. 3. On **deny**, stop. On **challenge**, demand the factor. On **no answer**, take the written default. 4. Only on **allow**, look for a live remembered-device record and skip the prompt if one exists. Stated as a rule: a remembered device can remove friction the ordinary path would have applied; it can never remove friction the verdict asked for. ## The fourth outcome: no answer Every integration eventually experiences the case where no verdict arrives before the sign-in path has to respond. The failure is not that it happens — it is that it is usually unnamed, so the behaviour is whatever some timeout path happens to do, and nobody knows which until it happens at scale. Name it. "No answer" is a fourth outcome in the contract with a written mapping, and the honest default is the **challenge**: - Mapping it to **allow** silently removes the control at the exact moment you have least information. It also fails quietly: nothing in your metrics looks different, because successful sign-ins are what you were expecting anyway. - Mapping it to **deny** turns a silent dependency into a total outage of sign-in for the whole membership — and for a small association that means nobody can see the watering rota all weekend. - Mapping it to **challenge** keeps everyone able to sign in while keeping the factor they enrolled. The cost is a prompt on machines that would have been skipped, which is the mildest of the three costs by a wide margin. The contract should also say what gets recorded. The sign-in path notes which branch it took — verdict received and what it was, verdict absent, device record present or not. Without that field a spike in denials and a spike in silence look identical from the outside, and at three in the morning that distinction is the whole diagnosis. ## Who owns the default This is the part that is an ownership question rather than an engineering one, and it is worth being explicit about in an interview. The risk service decides; the sign-in path enforces. Those are different components, usually different owners, and the temptation is to let the deciding side own the missing-answer case too, on the grounds that it is their service that went quiet. That is the wrong home. "What happens when we do not know" is a statement about **who is allowed into accounts**, and that is an authentication policy. It belongs to whoever owns authentication, alongside the lifetime of a remembered-device record and the width of the skip it buys — all three answer the same question about how much friction the service is willing to trade away. A practical consequence: the default must be written down and exercised *before* it is needed. A default that has never been tried is a guess, and the first time it runs will be during an incident, on the path every member uses. ## What a deny owes the person A refusal that is a dead end is a support ticket at best and a lost member at worst. A denied sign-in should record the reason in a form the association's committee can look up, and give the member some route back that does not depend on the same signal — typically a path that demands a stronger proof rather than one that simply repeats the refusal. The deny is a decision the service made about a person, and every such decision needs somewhere to be appealed.
- Why must the verdict be consulted before the remembered-device record rather than after?Because a remembered device is an input to the ordinary path, not an override of a decision. Look the record up first and a deny is unreachable for exactly the machines most worth denying — the ones already trusted, which is what an attacker who has taken over a member's laptop is holding. Verdict first makes the ordering rule enforceable: the record can remove friction the ordinary path would have applied, never friction the verdict asked for.
- What does this contract owe an operations team when denials spike at three in the morning?A recorded outcome per sign-in naming which branch ran: verdict received and what it was, verdict absent, device record present or not. Without it, a risk service that has started denying everything and a risk service that has gone silent produce the same symptom — members cannot get in — and the two have opposite remedies. With it, the two are one query apart and the decision to route around the service is a minute's work.
- Is defaulting a missing verdict to the challenge ever the wrong call?It can be, and the case is worth naming: if a large share of members have no second factor enrolled at all, the challenge is not a prompt for them, it is a refusal. Then the default has to say what happens to that population — typically let them through on the first factor and record it, while treating the gap as the real problem. The point stands either way: the behaviour is decided in advance and written down, not discovered during the outage.
saying these in an interview costs you the question
- Treating the verdict as a binary open-or-closed switch with no middle outcome.
- Reading allow as permission to skip the second factor entirely.
- Letting a remembered device override a deny because the machine is known.
- Leaving the no-answer case to whichever timeout path happens to run first.
- Denying a sign-in with no recorded reason and no route back for the member.
- Giving the deciding service ownership of what happens when it goes quiet.