How to use the hotp generator
- Enter your base32 secret in the first field. Spaces are ignored automatically.
- Set the counter value. This is the moving factor that increments with each authentication attempt.
- Choose the number of digits for the output code (6, 7 or 8).
- The HOTP code appears immediately as you type.
How HOTP works under RFC 4226
The HMAC-based one-time password algorithm combines a shared secret key with a counter using HMAC-SHA-1. The steps are:
- Convert the counter to an 8-byte big-endian integer.
- Compute
HMAC-SHA-1(key, counter_bytes), producing a 20-byte hash. - Extract 4 bytes from the hash using dynamic truncation: the offset is the lower nibble of the last byte, then read 4 bytes starting at that offset.
- Mask the most significant bit to avoid signed/unsigned issues, yielding a 31-bit integer.
- Reduce modulo
10^dwheredis the desired digit count, and pad with leading zeros.
For example, with the standard test secret 12345678901234567890 (base32: GEZDGNBVGY3TQOJQGEZDGNBVGY3TQOJQ) and counter 0, the HMAC-SHA-1 result is cc93cf18508d94934c64b65d8ba7667fb7cde4b0. Dynamic truncation yields the decimal value 1284755224, and taking modulo 1000000 gives the 6-digit code 755224.
RFC 4226 test vectors
The following table lists the official test vectors from Appendix D of RFC 4226. The shared secret is the ASCII string 12345678901234567890, which encodes to GEZDGNBVGY3TQOJQGEZDGNBVGY3TQOJQ in base32. You can paste this secret into the HOTP generator above to verify each code.
| Counter | HMAC-SHA-1 (hex) | Truncated (hex) | 6-Digit Code |
|---|---|---|---|
| 0 | cc93cf18508d94934c64b65d8ba7667fb7cde4b0 | 4c93cf18 | 755224 |
| 1 | 75a48a19d4cbe100644e8ac1397eea747a2d33ab | 41397eea | 287082 |
| 2 | 0bacb7fa082fef30782211938bc1c5e70416ff44 | 082fef30 | 359152 |
| 3 | 66c28227d03a2d5529262ff016a1e6ef76557ece | 66ef7655 | 969429 |
| 4 | a904c900a64b35909874b33e61c5938a8e15ed1c | 61c5938a | 338314 |
| 5 | a37e783d7b7233c083d4f62926c7a25f238d0316 | 33c083d4 | 254676 |
| 6 | bc9cd28561042c83f219324d3c607256c03272ae | 7256c032 | 287922 |
| 7 | a4fb960c0bc06e1eabb804e5b397cdc4b45596fa | 04e5b397 | 162583 |
| 8 | 1b3c89f65e6c9e883012052823443f048b4332db | 2823443f | 399871 |
| 9 | 1637409809a679dc698207310c8c7fc07290d9e5 | 2679dc69 | 520489 |
Base32 encoding for secrets
HOTP secrets are typically exchanged as base32 strings because the alphabet avoids visually ambiguous characters. Standard base32 uses A through Z and 2 through 7, with optional padding using the equals sign. When entering a secret into this HOTP generator, spaces and lowercase letters are handled automatically.
A common mistake is confusing base32 with base64. Base64 includes lowercase letters, digits, plus and slash, while base32 does not. If your authenticator app rejects a secret, verify that it is actually base32 encoded. For tools that handle other encoding formats, see the base64 encoder.
HOTP compared with TOTP
HOTP uses a counter that increments with each use, while TOTP (Time-based One-Time Password) replaces the counter with a timestamp divided by a time step, usually 30 seconds. Both rely on HMAC-SHA-1 and dynamic truncation, but their synchronization models differ.
Because HOTP depends on a counter, both the client and server must track it precisely. If they drift out of sync, the server typically checks a window of upcoming counter values to resynchronize. TOTP avoids this problem by deriving the moving factor from the current time, though it requires accurate clocks on both sides. If you need time-based codes instead, look for a TOTP tool rather than this HOTP generator.
Security considerations
The security of an HOTP system depends on keeping the shared secret confidential. If the secret is exposed, any party can generate valid codes for any counter value. The secret should be generated using a cryptographically secure random number generator and stored securely on both the client and server.
RFC 4226 recommends a minimum of 6 digits for the output code. Shorter codes reduce the search space for brute-force attacks. Servers should also implement throttling or lockout policies after a small number of failed attempts to prevent online guessing. Because this tool computes codes locally in the browser, it is useful for development and testing, but production systems should use audited cryptographic libraries on the server side.
Worked examples
| Example | Input | Result |
|---|---|---|
| RFC 4226 test vector (counter 0) | Base32 secret: GEZDGNBVGY3TQOJQGEZDGNBVGY3TQOJQ; Counter: 0; Digits: 6 | HOTP Code: 755224 |
| RFC 4226 test vector (counter 5) | Base32 secret: GEZDGNBVGY3TQOJQGEZDGNBVGY3TQOJQ; Counter: 5; Digits: 6 | HOTP Code: 254676 |
| RFC 4226 test vector (counter 9) | Base32 secret: GEZDGNBVGY3TQOJQGEZDGNBVGY3TQOJQ; Counter: 9; Digits: 6 | HOTP Code: 520489 |
| 8-digit code at counter 3 | Base32 secret: GEZDGNBVGY3TQOJQGEZDGNBVGY3TQOJQ; Counter: 3; Digits: 8 | HOTP Code: 26969429 |
FAQ
What is an HOTP generator?
An HOTP generator computes HMAC-based one-time passwords according to RFC 4226. It takes a shared base32 secret and a counter value, applies HMAC-SHA-1, and truncates the result to a short numeric code.
Why does my HOTP code not match my authenticator app?
Most authenticator apps default to TOTP, which uses the current time instead of a manual counter. Ensure your app is configured for event-based HOTP and that the counter matches exactly.
Is the base32 secret case sensitive?
No. Base32 decoding treats uppercase and lowercase letters identically. This tool normalizes the input automatically before decoding.
Can I use this HOTP generator offline?
Yes. All computation happens in your browser using a JavaScript HMAC-SHA-1 implementation. No data is sent to any server, so it works fully offline once the page is loaded.
What happens if the counter goes out of sync?
If the client counter is ahead of the server, authentication fails until the server catches up. Servers typically implement a look-ahead window to check several future counter values and resynchronize automatically.
How many digits should an HOTP code have?
RFC 4226 recommends at least 6 digits. Six digits provide one million possible values, which balances usability with resistance to brute-force guessing when combined with server-side throttling.