

0 / 2 embers
0 / 3000 xp
click for more info
Complete a lesson to start your streak
click for more info
Still calibrating
click for more info
Not enough gems
Cost: 6 gems
1: Multi-Factor Authentication
incomplete
2: TOTP
incomplete
3: Hardware Tokens
incomplete
4: Passkeys
incomplete
5: Choosing an MFA Method
incomplete
6: Account Recovery
incomplete
Back
ctrl+,
Next
ctrl+.
This lesson's interactive features are locked, please to keep using them
TOTP (Time-Based One-Time Password) generates short-lived codes from a shared secret and the current time. The codes are usually six digits and rotate on a 30-second time step.
Its appeal is low friction: it works offline in an authenticator app and doesn't require a separate hardware security key.
TOTP is built on a unique shared secret known to both the server and the user's authenticator. Both sides independently compute the expected code for the current time step. Here's some pseudocode. Assume that sharedSecret is stored on the server and in the user's authenticator app, and userSuppliedCode is the code the user entered during login:
timeStep = floor((unixTime - T0) / 30);
serverComputedCode = HOTP(sharedSecret, timeStep);
if (serverComputedCode === userSuppliedCode) {
// TOTP code accepted
} else {
// TOTP code rejected
}
The shared secret is not sent during login, but the generated code is. If both clocks and algorithm settings agree, the server computes the same value and checks whether they match.
Because codes are so short, servers need to be careful to rate-limit guesses so an attacker can't brute-force them.
You're probably familiar with this process, but the way users get the shared secret on their device during setup is typically:
Devices get lost, so recovery codes are often provided as a fallback. They're one-time secrets that can be used in place of a TOTP code. The user is expected to download and store them in a safe place, like a password manager.
TOTP codes can be phished. A six-digit code can be typed into a fake login page and relayed to the real site. TOTP is stronger than a password alone, but it isn't phishing-resistant like a FIDO2/WebAuthn authenticator.
Bearly Secure's TOTP flow is working, but it accepts the same authenticator code more than once during its 30-second time step.
Prevent TOTP-code replay. In src/auth/totp.ts, fix the verifyAndConsumeTotpCode function:
With Bearly Secure still running, run and submit the CLI tests from the project root.