mirror of
https://github.com/XFox111/SimpleOTP.git
synced 2026-04-23 08:08:40 +03:00
Created Code generation/validation (markdown)
@@ -0,0 +1,69 @@
|
||||
# Code generation/validation
|
||||
Here we will look at how to generate an OTP on client side and validate it on server side
|
||||
|
||||
## Code generation
|
||||
### Time-based OTP
|
||||
For TOTP it's quite simple: you load your OTP configuration from your storage (in this example it's `Xamarin.Essentials.Preferences`) and then generate a new OTP code with `OTPService`
|
||||
```csharp
|
||||
OTPConfiguration totpConfig = JsonConvert.DeserializeObject<OTPConfiguration>(Preferences.Get("myTotpConfig", ""));
|
||||
|
||||
OTPCode code = OTPService.GenerateCode(ref totpConfig);
|
||||
Debug.WriteLine(code); // OTPasswordModel { Code = 350386, Expiring = 23-May-21 06:08:30 PM }
|
||||
```
|
||||
|
||||
### HMAC-based OTP
|
||||
For HOTPs it's important to update your configuration after code generation because it's based on a counter which should be incremented each time you generate a password:
|
||||
```csharp
|
||||
OTPConfiguration hotpConfig = JsonConvert.DeserializeObject<OTPConfiguration>(Preferences.Get("myHotpConfig", ""));
|
||||
|
||||
OTPCode code = OTPService.GenerateCode(ref hotpConfig);
|
||||
Debug.WriteLine(code); // OTPasswordModel { Code = 350386, Expiring = null } // Since HOTP isn't time related, it doesn't have expiration time
|
||||
Preferences.Set("myHotpConfig", JsonConvert.SerializeObject(hotpConfig)); // It's important to update configuration to prevent desynchronization with server
|
||||
```
|
||||
It's also recommended to not let user generate HOTP in one action. Make sure you've notified user that generating code for no reason can cause a desynchronization with the server, thus inability to log in
|
||||
|
||||
## Code validation
|
||||
### Time-based OTP
|
||||
Code validation is quite like what we do with code generation. In this example as storage location, we will use an `DatabaseContext` from ASP.NET since usually validation occurs on server side
|
||||
```csharp
|
||||
[HttpGet]
|
||||
public IActionResult Get(int code, Guid id)
|
||||
{
|
||||
OTPConfiguration totpConfig = db.Configs.Find(id);
|
||||
if (OTPService.ValidateTotp(code, totpConfig, TimeSpan.FromSeconds(30)))
|
||||
return Ok();
|
||||
else
|
||||
return Forbidden();
|
||||
}
|
||||
```
|
||||
`TimeSpan.FromSeconds(30)` here is tolerance time which defines a set of periods, thus OTP codes which are valid at that moment. This is used to handle time desynchronization between server and client. If `OTPConfiguration.Period` is equal to 30 seconds, this tolerance time suggests that at that moment there're 3 valid OTP codes: current one, previous one and next one:
|
||||
```
|
||||
t - 30 t t + 30
|
||||
| | |
|
||||
| (n - 1)-th period | n-th period | (n + 1)-th period |
|
||||
```
|
||||
|
||||
Recommended tolerance time: 30 seconds
|
||||
|
||||
### HMAC-based OTP
|
||||
Similar to code generation, after code validation you need to update configuration in your storage. Note that HOTP counter increments only on successful validation
|
||||
```csharp
|
||||
[HttpGet]
|
||||
public IActionResult Get(int code, Guid id)
|
||||
{
|
||||
OTPConfiguration hotpConfig = db.Configs.Find(id);
|
||||
if (OTPService.ValidateHotp(code, ref hotpConfig, 1, true)) // 1 - toleranceSpan; true - resyncCounter
|
||||
{
|
||||
db.Update(hotpConfig);
|
||||
db.SaveChanges();
|
||||
return Ok();
|
||||
}
|
||||
else
|
||||
return Forbidden();
|
||||
}
|
||||
```
|
||||
For HOTP configuration tolerance span is presented in number of preceding and subsequent counters which should be treated as valid. Last parameter is `resyncCounter` and determines if `OTPService.ValidateHotp` should update counter according to provided OTP code
|
||||
|
||||
Recommended tolerance span: 1-2
|
||||
|
||||
It is also recommended to dismiss validated code to prevent from using it second time
|
||||
Reference in New Issue
Block a user