Whiteboard challenge

Login Code: ending the resend loop

A waiting state for the security code step of a banking app login.

FormatWhiteboard exercise
PlatformNative mobile
DateOctober 2026
Three screens of the Cherry banking app: the log in screen, the security code screen with a countdown and a locked resend button, and the timeout screen where resend is active again

The challenge

Redesign the security code step of a banking app login. Users say they tap resend several times before a code arrives. Cherry is a made-up bank that I used for this exercise.

Diagnosis before design

The complaint is that the code does not arrive on the first try. I separated what the user sees from what he concludes. He sees that he tapped, no code came, he tapped again several times, and then a code came. He concludes that the first one was never sent. From his side of the screen he has no way to know which tap produced the code that arrived.

That left two places where the problem could be.

On a real team I would check the send logs first: one message per tap, and whether each was delivered or failed. In this exercise I had no logs, so I stated my assumption and designed for it.

My assumption: the text is delivered, but each extra tap sends a new code and cancels the previous one. His own tapping is part of the failure, and he taps because the screen gives him no feedback.

A waiting state for Cherry clients who can't log in, to end the repeated tapping caused by no feedback between the tap and the handoff.

I deliberately left the carrier delivery problem to the SMS provider team.

One user, one situation

Pain points and priorities

FrustrationDecisionWhy
No sign that his request is in progress, so he keeps tappingSolvingIt is what stops him logging in tonight, and the app team owns it.
A code is required at every loginLeft outIt is a security requirement and it works as intended.
“Remember me” does not save the passwordLeft outIt saves the Login ID by design. It annoys him, but it does not block the login.
The text message is slow or never deliveredLeft outIt belongs to the SMS provider team.

The flow

  1. He opens the app. His Login ID is already filled in, because “Remember me” is on by default.
  2. He enters his password and taps “Send security code.”
  3. The waiting state starts: the screen says where the code was sent, a 30 second countdown runs, and resend is locked.
  4. If the code arrives, the app fills it in. He is logged in and pays the bill.
  5. If 30 seconds pass with no code, the screen says so and resend unlocks. He taps it and the waiting state starts again.
  6. After a second timeout, the screen offers a phone call or an email, so he is never stuck.

The key screens

  1. Log in. One primary action. The button names what happens next: “Send security code.”
  2. Waiting. The largest element is the “Code sent” card with the live countdown, because that reassurance is what stops him tapping. The locked button shows three signals and never colour alone: a muted fill, new text (“Resend in 0:24”), and a spinner.
  3. Timeout. The card changes to “The code didn't arrive” and the button returns to full colour with “Resend security code.” It also tells him the first code will stop working.
The three Cherry screens side by side: log in with a saved Login ID, the waiting state with a Code sent card, a 0:24 countdown and a locked Resend button, and the timeout state with an active Resend security code button

Three questions I had to answer

Edge cases

How I would know it works

The share of login attempts that end in a successful login within two minutes of the first code request.

What I would do differently

The screens were drawn with Claude from my design decisions. Cherry is a made-up bank, and the Login ID and phone number are sample data.

All whiteboard challenges →