Skip to content

Instantly share code, notes, and snippets.

@bilal-fazlani
Last active April 25, 2024 21:40
Show Gist options
  • Save bilal-fazlani/593c833bb057c1365baa5747a9f135fa to your computer and use it in GitHub Desktop.
Save bilal-fazlani/593c833bb057c1365baa5747a9f135fa to your computer and use it in GitHub Desktop.
OTP generation and validation
Config name Section Type Description
secret Both string  
length Generation int 6,7,8 digits of OTP
expiry-duration Generation duration 1m, 30s
otp-buffer-window Validation int expiry period multiplier
generation-limit Generation int Consecutive generation limit. After a successful validation, this resets to zero
resend-interval Generation duration can re-send only after this duration of last send
validation-limit Validation int Consecutive validate limit when validate keeps failing. if a validates succeeds, this counter resets to zero
cool-off-period Both duration Validation and generation are blocked for this period when user is blocked
//OTP generation
//services
trait NotificationService:
def sendOTP(otp: String): Unit
//config values
val generationLimit: Int = ???
val resendInterval: Duration = ???
val cooldown: Duration = ???
//api input
enum UserIdentifier:
case Email(email: String)
case Phone(phone: String)
enum OTPType:
case Transaction(tranasctionId: String)
case Login(id: UserIdentifier)
case class GenerateOTP(otpType: OTPType)
//api output
enum Response:
//OTP generated successfully
case Success(id: UUID, attemptsRemaining: Int)
//OTP generation failed because of resend interval
case TooSoon(timeRemaining: Duration)
//OTP generation failed because account is locked for some time
case TooManyAttempts(timeRemaining: Duration)
//db record
case class OTPRecord(
id: UUID,
generationCounter: Int,
allowGenerationAfter: DateTime,
ttl: DateTime,
otpType: OTPType
)
//current time
val currentTime: DateTime = ???
val record: OTPRecord = ???
//check if OTP can be generated
val canGenerate =
currentTime.isAfter(record.allowGenerationAfter) && record.generationCounter < generationLimit
if (canGenerate)
val newOTP = generateOTP()
NotificationService.sendOTP(newOTP)
val newGenerationCounter = generationCounter + 1
if newGenerationCounter == generationLimit
val newAllowGenerationAfter = currentTime.plus(cooldown)
updateDB(newGenerationCounter, newAllowGenerationAfter, TTL(newAllowGenerationAfter))
else
val newAllowGenerationAfter = currentTime.plus(resendInterval) //1 min
val ttl = currentTime.plus(cooldown) // 1 day
updateDB(newGenerationCounter, newAllowGenerationAfter, ttl)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment