GM.OTP.Domain
1.1.0
dotnet add package GM.OTP.Domain --version 1.1.0
NuGet\Install-Package GM.OTP.Domain -Version 1.1.0
<PackageReference Include="GM.OTP.Domain" Version="1.1.0" />
<PackageVersion Include="GM.OTP.Domain" Version="1.1.0" />
<PackageReference Include="GM.OTP.Domain" />
paket add GM.OTP.Domain --version 1.1.0
#r "nuget: GM.OTP.Domain, 1.1.0"
#:package GM.OTP.Domain@1.1.0
#addin nuget:?package=GM.OTP.Domain&version=1.1.0
#tool nuget:?package=GM.OTP.Domain&version=1.1.0
<p align="center"> <img src="https://raw.githubusercontent.com/gmetskhvarishvili/GM.OTP/master/icon.png" alt="GM.OTP" width="140" height="140" /> </p>
GM.OTP
A lightweight, storage-agnostic one-time password (OTP) core for .NET. OtpManager generates and
verifies codes over pluggable code-generation, hashing, and clock abstractions — binding each code to
its subject and destination so a tampered row can't be verified. Part of the GM.* family of
packages. Targets net10.0.
Packages
This repository ships three packages that version and release in lockstep:
| Package | What it provides |
|---|---|
GM.OTP |
OtpManager (generate/verify), options, request/result models. |
GM.OTP.Domain |
The OtpChallenge aggregate and the ICodeGenerator / ICodeHasher / IDateTimeProvider abstractions. |
GM.OTP.Persistence |
The EF Core configuration for OtpChallenge. |
Install
dotnet add package GM.OTP
Use
Provide implementations of the three abstractions (how you generate codes, hash them, and read the clock), then generate and verify:
var manager = new OtpManager(codeGenerator, codeHasher, dateTimeProvider, new OtpOptions
{
CodeLength = 6,
ExpirationMinutes = 2,
MaxAttempts = 5,
});
// Issue a code for a subject (e.g. a user) + destination (e.g. an email/phone).
OtpGenerationData data = manager.Generate(subject: "user-42", destination: "user@example.com");
// Persist a challenge built from `data` (hash, salt, expiry, max attempts), then send `data.PlainCode`.
var challenge = new OtpChallenge(
"user-42", "user@example.com", data.CodeHash, data.Salt,
OtpPurposes.Login, data.ExpiresAtUtc, data.MaxAttempts);
// Later, verify the code the user entered:
VerifyOtpResult result = manager.Verify(challenge, "123456");
if (result.IsValid) { /* proceed */ }
How it protects codes
- Salted, subject/destination-bound hashes — the stored hash covers
code + subject + destination, so verification fails if any of those columns were altered. - Single use — a verified challenge is marked used and can't be replayed.
- Attempt limiting — each failed attempt is counted; exceeding
MaxAttemptsthrowsOtpMaxAttemptsExceededException. - Expiry — codes expire after
ExpirationMinutes.
Contributing & releases
Versioning is automated from Conventional Commits — see CONTRIBUTING.md. All three packages release together under one version.
License
MIT — see LICENSE.
| Product | Versions Compatible and additional computed target framework versions. |
|---|---|
| .NET | net10.0 is compatible. net10.0-android was computed. net10.0-browser was computed. net10.0-ios was computed. net10.0-maccatalyst was computed. net10.0-macos was computed. net10.0-tvos was computed. net10.0-windows was computed. |
-
net10.0
- GM.EntityFramework.Domain (>= 1.2.1)
NuGet packages (2)
Showing the top 2 NuGet packages that depend on GM.OTP.Domain:
| Package | Downloads |
|---|---|
|
GM.OTP.Persistence
EF Core persistence for the GM.OTP stack: the OtpChallenge entity configuration. Part of the GM.OTP family. |
|
|
GM.OTP
A lightweight, storage-agnostic one-time password (OTP) core for .NET. OtpManager generates and verifies codes over pluggable code-generation, hashing, and clock abstractions, binding each code to its subject and destination. Part of the GM.OTP family. |
GitHub repositories
This package is not used by any popular GitHub repositories.
| Version | Downloads | Last Updated |
|---|---|---|
| 1.1.0 | 128 | 8/1/2026 |