Codes, links, and approval prompts
Another way to sign in
After entering a password at Cedar Inc., Avery is asked for a code. On another site, Avery can sign in by clicking a link sent by email. Both methods rely on a short-lived secret, but the way Avery receives it and the checks the service performs can differ.
Delivered codes and links
For a text-message code, the service sends a temporary secret to the phone number Avery registered earlier. Avery types that code into the sign-in page. A correct code shows access to messages sent to that number at that moment. It does not prove that Avery alone controls the number or phone.
That distinction matters because phone numbers can be reassigned and an attacker can sometimes move a number to another SIM. A message can also be seen by someone other than its intended recipient. For these reasons, the NIST guidance mentioned in Passwords and PINs treats codes sent by text message or voice call as a restricted option: a service that offers them should explain the risk and give people a stronger alternative.
An email code depends on access to Avery's mailbox. A mailbox can usually be opened from any device with the right password, so a correct code shows that someone can read Avery's mail, not that they hold a particular phone or computer. A magic link works similarly, except the secret is part of a link that the service checks when Avery opens it. Someone who can read or forward Avery's mail may be able to use either method.
A delivered code or link should work only for its intended account, purpose, and short time window. Once used, it must not work again, even if two requests arrive together. Email services sometimes open links automatically to scan them, so merely fetching a magic link should not unexpectedly sign Avery in or consume it.
Authenticator-app codes
An authenticator app generates codes without waiting for a new message. During enrollment, the service generates a secret and shows it to Avery, usually as a QR code, which the app scans and stores. From then on, the service and the app hold the same value, the shared-secret pattern from Secrets and key pairs. Anyone who copies that QR code, or the secret inside it, can generate Avery's future codes too.
Time-based one-time passwords (TOTP) use the shared secret and the current time to calculate a short code. The service calculates the expected code independently from its own copy of the secret, so its stored secrets need the same protection as the app's.
Because clocks can differ slightly, the service may accept codes within a small time window. It also limits guesses and must not accept a code again after a successful use. If Avery types a current code into a fake site, however, someone can relay it to the real service before it expires. A changing code is still something a phishing page can ask for.
Approval prompts
Instead of asking Avery to type a code, a service can send an approval request to an enrolled app. The response must come from that app and belong to the sign-in attempt Avery is completing.
If someone else starts a sign-in with Avery's password, Avery might receive a prompt without expecting one. Repeated prompts can wear a person down until they approve one just to make the prompts stop.
Number matching is designed to stop that. The sign-in page shows a number, and the app asks Avery to enter it before approving. If Avery did not start the sign-in, there is no number on Avery's screen to enter, so a tired tap on an unexpected prompt is no longer enough. Number matching does not stop a phishing relay, though. If Avery signs in on a fake page that passes everything to the real service, the fake page can show the real number, and Avery's approval completes the attacker's sign-in.
Avery should deny an unexpected prompt and investigate through a trusted route. If the request is denied, expires, or cannot reach the app, the sign-in attempt has not succeeded.
Following a code
Here is a simulated request for a delivered code. The address and values are fictional; the example does not send a real request.
POST https://login.cedar.example/sign-in/verify-code
Content-Type: application/json
{"attempt_id":"example-attempt","code":"000000"}
HTTP/1.1 400 Bad Request
Content-Type: application/json
{"error":"Code could not be accepted. Start a new attempt."}
Suppose those digits match a code sent earlier, but the sign-in attempt has expired. The response rejects it. Matching digits alone would not be enough; the service also needs to check:
| Check | Why it matters |
|---|---|
| Account and purpose | A recovery code must not accidentally become a sign-in or email-change approval. |
| Pending attempt | Evidence must complete the intended interaction. |
| Lifetime and unused state | An expired or consumed secret must fail, including concurrent reuse. |
| Guess limits | A short code has a small search space and needs abuse controls. |
Even when every check passes, each method in this lesson depends on something Avery can read, type, or approve, and a convincing fake page can ask for any of them. The next lesson, Security keys, passkeys, and biometrics, turns to methods where the service holds only a public key and the browser ties each response to the real website.