A small and easy-to-use one-time password generator for Java according to RFC 4226 (HOTP) and RFC 6238 (TOTP).
The following features are supported:
- Generation of secrets
- Time-based one-time password (TOTP, RFC 6238) generation based on current time, specific time, OTPAuth URI and more for different HMAC algorithms.
- HMAC-based one-time password (HOTP, RFC 4226) generation based on counter and OTPAuth URI.
- Verification of one-time passwords
- Generation of OTP Auth URI's
<dependency>
<groupId>com.github.bastiaanjansen</groupId>
<artifactId>otp-java</artifactId>
<version>1.3.2</version>
</dependency>
implementation 'com.github.bastiaanjansen:otp-java:1.3.2'
libraryDependencies += "com.github.bastiaanjansen" % "otp-java" % "1.3.2"
<dependency org="com.github.bastiaanjansen" name="otp-java" rev="1.3.2" />
Or you can download the source from the GitHub releases page.
To create a HOTP
instance, use the HOTP.Builder
class as follows:
byte[] secret = "VV3KOX7UQJ4KYAKOHMZPPH3US4CJIMH6F3ZKNB5C2OOBQ6V2KIYHM27Q".getBytes();
HOTP.Builder builder = new HOTP.Builder(secret);
HOTP hotp = builder.build();
The above builder creates a HOTP instance with default values for passwordLength = 6 and algorithm = SHA1. Use the builder to change these defaults:
HOTP.Builder builder = new HOTP.Builder(secret);
builder
.withPasswordLength(8)
.withAlgorithm(HMACAlgorithm.SHA256);
HOTP hotp = builder.build();
When you don't already have a secret, you can let the library generate it:
// To generate a secret with 160 bits
byte[] secret = SecretGenerator.generate();
// To generate a secret with a custom amount of bits
byte[] secret = SecretGenerator.generate(512);
It is also possible to create a HOTP instance based on an OTPAuth URI. When algorithm or digits are not specified, the default values will be used.
URI uri = new URI("otpauth://hotp/issuer?secret=ABCDEFGHIJKLMNOP&algorithm=SHA1&digits=6&counter=8237");
HOTP hotp = HOTP.fromURI(uri);
Get information about the generator:
byte[] secret = hotp.getSecret();
int passwordLength = hotp.getPasswordLength(); // 6
HMACAlgorithm algorithm = hotp.getAlgorithm(); // HMACAlgorithm.SHA1
After creating an instance of the HOTP class, a code can be generated by using the generate()
method:
try {
int counter = 5;
String code = hotp.generate(counter);
// To verify a token:
boolean isValid = hotp.verify(code, counter);
// Or verify with a delay window
boolean isValid = hotp.verify(code, counter, 2);
} catch (IllegalStateException e) {
// Handle error
}
TOTP can accept more paramaters: passwordLength
, period
, algorithm
and secret
. The default values are: passwordLength = 6, period = 30 and algorithm = SHA1.
// Generate a secret (or use your own secret)
byte[] secret = SecretGenerator.generate();
TOTP.Builder builder = new TOTP.Builder(secret);
builder
.withPasswordLength(6)
.withAlgorithm(HMACAlgorithm.SHA1) // SHA256 and SHA512 are also supported
.withPeriod(Duration.ofSeconds(30));
TOTP totp = builder.build();
Or create a TOTP
instance from an OTPAuth URI:
URI uri = new URI("otpauth://totp/issuer?secret=ABCDEFGHIJKLMNOP&algorithm=SHA1&digits=6&period=30");
TOTP totp = TOTP.fromURI(uri);
Get information about the generator:
byte[] secret = totp.getSecret();
int passwordLength = totp.getPasswordLength(); // 6
HMACAlgorithm algorithm = totp.getAlgorithm(); // HMACAlgorithm.SHA1
Duration period = totp.getPeriod(); // Duration.ofSeconds(30)
After creating an instance of the TOTP class, a code can be generated by using the now()
method, similarly with the HOTP class:
try {
String code = totp.now();
// To verify a token:
boolean isValid = totp.verify(code);
} catch (IllegalStateException e) {
// Handle error
}
The above code will generate a time-based one-time password based on the current time. The API supports, besides the current time, the creation of codes based on timeSince1970
in seconds, Date
, and Instant
:
try {
// Based on current time
totp.now();
// Based on specific date
totp.at(new Date());
// Based on seconds past 1970
totp.at(9238346823);
// Based on an instant
totp.at(Instant.now());
} catch (IllegalStateException e) {
// Handle error
}
To easily generate a OTPAuth URI for easy on-boarding, use the getURI()
method for both HOTP
and TOTP
. Example for TOTP
:
TOTP totp = new TOTP.Builder(secret).build();
URI uri = totp.getURI("issuer", "account"); // otpauth://totp/issuer:account?period=30&digits=6&secret=SECRET&algorithm=SHA1
Often, services provide "backup codes" or "recovery codes" which can be used when the user cannot access the 2FA device anymore. Often because 2FA device is a mobile phone, which can be lost or stolen.
Because recovery code generation is not part of the specifications of OTP, it is not possible to generate recovery codes with this library and should be implemented seperately.
OTP-Java is available under the MIT License. See the LICENCE for more info.