EzOTP
A simple, easy-to-use one-time password generator implementation for .NET Core 3.1. Compatible with Google Authenticator.
Install / Use
/learn @Emzi0767/EzOTPREADME
EzOTP
A simple, lightweight, and easy to use implementation of One-Time Password protocol, both time-based and counter-based variants.
Installation
To start using the package, just install it from NuGet.
Usage
The library is designed to be fairly straightforward and easy to use.
Basic usage
The primary use case for the library is usage from QR codes, or other media containing OTP authentication
URIs (that is, URIs with otpauth scheme).
var otp = OtpGenerator.ParseUri("otpauth://totp/ACME%20Co:john@example.com?secret=DGW24UIKQZBELXEMY64PICAL5IGYMJM6&issuer=ACME%20Co&algorithm=SHA1&digits=6&period=30");
var code = otp.GenerateCode();
This will generate a code in XXXXXX format, as a string.
Generate raw code
In the event a numeric code is more desired (e.g. for comparison purposes), one can use GenerateRaw() method instead.
It returns an integer with appropriate number of digits.
var otp = OtpGenerator.ParseUri("otpauth://totp/ACME%20Co:john@example.com?secret=DGW24UIKQZBELXEMY64PICAL5IGYMJM6&issuer=ACME%20Co&algorithm=SHA1&digits=6&period=30");
var code = otp.GenerateRaw();
Groupping digits
groupSize argument of GenerateCode() defines a maximum number of digits in a single group. For example, if the
generator is configured for generating 6 digit-long codes, the output looks like so, depending on the value of
groupSize argument:
- 1:
X X X X X X - 2:
XX XX XX - 3:
XXX XXX - 4:
XX XXXX - 5:
X XXXXX - 6+:
XXXXXX
Handling desynchronization
Desynchronization between 2 generators can occur. Because of this, EzOTP provides 2 ways of handling potentially-desynchronized generators.
Method 1: Offset
If the desynchronization offset of both counters is known, one can use offset argument of GenerateCode() method.
This will add a fixed offset to generated counter values, without changing the counter value itself.
For example, using Google Authenticator-compatible examble from Basic usage section, let's assume the desynchronization between the two devices is between 60 and 90 seconds, such that current application is lagging.
Since Google Authenticator uses periods of 30 seconds, this means we have to add 60 / 30 = 2 periods to the counter,
meaning we need to use an offset of 2:
var otp = OtpGenerator.ParseUri("otpauth://totp/ACME%20Co:john@example.com?secret=DGW24UIKQZBELXEMY64PICAL5IGYMJM6&issuer=ACME%20Co&algorithm=SHA1&digits=6&period=30");
var code = otp.GenerateCode(offset: 2);
Should the current application be the one ahead, an offset of -2 would be applied instead.
Method 2: Counter window
For authenticating, RFC actually recommends testing several codes in the past and future. However generating several codes using above methods is not the best choice, as it does trip the counter internally, meaning that if the generator type uses a counter (that is, is a HOTP generator), it will increase the internal counter value for every code generated.
To alleviate this issue, EzOTP provides methods for generating a "window" of codes, whilst incrementing the counter only once.
Assuming that user-provided code is in an int variable called userCode, one can validate their input like so:
var otp = OtpGenerator.ParseUri("otpauth://totp/ACME%20Co:john@example.com?secret=DGW24UIKQZBELXEMY64PICAL5IGYMJM6&issuer=ACME%20Co&algorithm=SHA1&digits=6&period=30");
if (!otp.GenerateRawWindow(window: 1).Contains(userCode))
// fail the authentication process
The method optionally takes a window argument, which defines the window size. Given a window size of n, EzOTP will
generate n codes before current counter value, 1 current counter value code, and n codes after current counter
value.
Specifying a value of 0 or a negative number will use default window sizes. For TOTP it's 1, for HOTP it's 2.
OTP generator configuration
An OTP generator can be constructed without parsing an URI, by constructing an instance of OtpGeneratorConfiguration
directly. It's an abstract class, which serves as a common base for 2 configuration types:
TotpGeneratorConfiguration: Contains TOTP-specific properties.HotpGeneratorConfiguration: Contains HOTP-specific properties.
The configuration instance can then be supplied to the constructor of OtpGenerator. This allows for storing OTP
generator state and restoring it without having to use URIs. This is useful for HOTP particularly, where the counter
value has to be re-recorded after every generation.
Generating Google Authenticator URIs
One can easily generate configurations for Google Authenticator, by using GenerateGoogleAuthenticator() static method
on either TotpGeneratorConfiguration or HotpGeneratorConfiguration classes.
These methods return configuration objects, that can then be plugged into OtpGenerator constructor, or just returned
as an URI to a user.
Support me
Lots of effort went into making this software.
If you feel like I'm doing a good job, or just want to throw money at me, you can do so through any of the following:
Other questions
If you have other questions or would like to talk in general, feel free to visit my Discord server.
Related Skills
node-connect
342.0kDiagnose OpenClaw node connection and pairing failures for Android, iOS, and macOS companion apps
frontend-design
84.7kCreate distinctive, production-grade frontend interfaces with high design quality. Use this skill when the user asks to build web components, pages, or applications. Generates creative, polished code that avoids generic AI aesthetics.
openai-whisper-api
342.0kTranscribe audio via OpenAI Audio Transcriptions API (Whisper).
commit-push-pr
84.7kCommit, push, and open a PR

