Careful with that validates? function. Your OTP only changes every 30 seconds by default. At six digits, you're at non-trivial risk of just getting hit by exhaustive search in that interval. Additionally, since the == method on strings short circuits in Ruby, if they wanted to get really tricky they could possibly even get local network access and do a timing attack on you. (At 30 seconds a go and only 10^6 possibilities it would probably be easier to exhaustively search, though.)