Security requirement
Authenticator app codes are usually a second factor. In this system, the OTP code is the only factor, so it needs dramatically more entropy.
The math
6-digit numeric: 10^6 = 1,000,000 combinations8-character alphanumeric: 36^8 = 2,821,109,907,456 combinationsWhy it matters
Storage model
A-Z and 0-9.userAuthAttempts.const codeHash = hashOTPCode(code); await db.insert(userAuthAttempts).values({ email: user.email, userId: user.id, codeHash, purpose: 'login', expiresAt: new Date(Date.now() + 15 * 60 * 1000), used: false, });
Token verification
export const Route = createFileRoute('/login-via-code/$token')({ beforeLoad: async ({ params }) => { await verifyCodeVerificationToken(params.token); return { tokenValid: true }; }, component: LoginViaCodePage, });