Classic: Microsoft Defender Safe Links (and similar scanners) open every link in incoming mail to check it. That GET request uses up the one-time token. When the human clicks, it's already spent.
Fix: the link in the email must not log anyone in by itself. Make it land on a page with a "Continue to log in" button, and only call verifyOtp with the token_hash when the button is clicked. Scanners fetch the page but don't press buttons.
Or skip links for these customers and send the 6-digit code instead.