README.md in rotp-3.2.0 vs README.md in rotp-3.3.0

- old
+ new

@@ -53,9 +53,42 @@ # OTP verified with a counter hotp.verify("316439", 1401) # => true hotp.verify("316439", 1402) # => false ``` +### Verifying a Time based OTP with drift + +Some users devices may be slightly behind or ahead of the actual time. ROTP allows users to verify +an OTP code with an specific amount of 'drift' + +```ruby +totp = ROTP::TOTP.new("base32secret3232") +totp.now # => "492039" + +# OTP verified for current time with 120 seconds allowed drift +totp.verify_with_drift("492039", 60, Time.now - 30) # => true +totp.verify_with_drift("492039", 60, Time.now - 90) # => false +``` + +### Preventing reuse of Time based OTP's + +In order to prevent reuse of time based tokens within the interval window (default 30 seconds) +it is necessary to store the last time an OTP was used. The following is an example of this in action: + +```ruby +User.find(someUserID) +totp = ROTP::TOTP.new(user.otp_secret) +totp.now # => "492039" + +user.last_otp_at # => 1472145530 + +# Verify the OTP +verified_at_timestamp = totp.verify_with_drift_and_prior("492039", 0, user.last_otp_at) #=> 1472145760 +# Store this on the user's account +user.update(last_otp_at: verified_at_timestamp) +verified_at_timestamp = totp.verify_with_drift_and_prior("492039", 0, user.last_otp_at) #=> false +``` + ### Generating a Base32 Secret key ```ruby ROTP::Base32.random_base32 # returns a 16 character base32 secret. Compatible with Google Authenticator ```