OTP Best Practices for Developers: Length, Expiry, Attempts and Resend Rules
A one-time code is only as strong as the rules around it. A six-digit code with unlimited guesses can be broken. A code that never expires can be reused. These defaults are a starting point you should adjust to your own risk.
Length and format
- Six digits is common and easy to type. Longer codes are harder to guess but harder for users.
- Generate with a secure random source, not with a time-based or sequential value.
- Do not reuse a code across users or sessions.
Expiry
- Keep the life short, from a few minutes to ten at most.
- Invalidate the code once it is used.
- Invalidate the old code when a new one is sent.
Attempts
- Allow a small number of wrong tries, for example five.
- Lock or slow down after that and require a new code.
- Count attempts per account and per number, not only per IP.
Resend rules
- Add a resend timer of about thirty to sixty seconds.
- Limit the number of sends per hour.
- Return the same message whether or not the number exists, so you do not reveal who has an account.
Storage
Store a hash of the code, not the code, with an expiry time and an attempt counter. Compare in constant time.
Messages
- Say what the code is for and who sent it.
- Say that you will never ask for it by phone.
- Do not include links that ask users to log in.
Test your own flow
Run your sign-up test with a virtual number or the temporary email flow, so you see the same delay and format a real user sees.
A sample policy
| Setting | Starting value |
|---|---|
| Code length | Six digits |
| Lifetime | Five minutes |
| Wrong attempts | Five |
| Resend timer | Thirty to sixty seconds |
| Sends per hour | Three to five |
Review it against your risk
A payment code needs stricter values than a newsletter confirmation. Write down the risk of each flow and pick settings that fit. Revisit them when you see abuse.
Questions people ask
Is an SMS code strong enough?
For many uses yes, but an authenticator app or passkey is stronger for important accounts.
Should the code be numeric?
Numeric is easiest to type and to autofill.
Related guides and pages
Create a free OtpGet account and try it with a small balance.