I'm implementing my own 2 factor authentication using SMS.

We have a gift card service and the users are sent a link to their gift card. Every time they click on their link, we are verifying it's them by sending an SMS to their phone and prompting them for the code on our site.

I just want to make sure I haven't overlooked anything.

We first ask a user for their phone number and this is saved in a table called giftee_verification_details:

orderId | phoneNumber
1       |  +35312345

The server then generates a random 4 digit code and saves in sms_codes table:

id   |   orderId    |    code   |   createdTimestamp     |  codeValidUntil
1    |      255     |   8145    |   2019-01-17 10:28:58  |   2019-01-17 10:33:58

codeValidUntil is the time the code is valid until - in this case 5 minutes from when the code was created.

We send this to the user's phone. When the user submits this, we check the code is correct and within the correct timeframe, then create a row in a table called sms_login:

id    |     smsCodeId     |    createdTimestamp    |    loginValidUntil
1     |         1         |   2019-01-17 10:39:25  |     2019-01-17 11:39:25

loginValidUntil is the time this 'login' is valid for. So a user can view their gift card details if the current time is less than the last loginValidUntil. If the current time is after this, we redirect, send them another sms code and ask for it in our UI.

Are there any problems with this approach?

  • What does the link to the gift card look like? Is it predictable in any way? Jan 17, 2019 at 14:36
  • The url has a random 6 character length key...
    – Mark
    Jan 17, 2019 at 15:22
  • From the data standpoint, it looks like you're storing a bunch of unnecessary in the database (sms_code mainly). Once a code is validated, there is no reason to keep it around, its job is done and it can't be reused, so don't waste table space on it (keep it as a temp line in a memtable until then). That also means the smsCodeId column in sms_login is extra.
    – Ruscal
    Jan 17, 2019 at 22:13
  • Additional thought. While I applaud trying to create your own auth scheme, have you considered using free/open-source 2FA libraries? Most of those have already solved these problems, and are supported by a decent bunch of security nuts who live to make the whole process better. I've used LinOTP ( linotp.org ) with great effect, and that would also account for @ThoriumBR 's point about using "better" OTP methods (you can just as easily turn on TOTP and HOTP as SMS-code)
    – Ruscal
    Jan 17, 2019 at 22:17
  • @Ruscal thanks, i've mad the sms_code change. linotp looks interesting, may go down this road in the future
    – Mark
    Jan 18, 2019 at 14:05

1 Answer 1


I don't see any glaring security issue with this, except for I don't really trust SMS for 2FA. I prefer TOTP codes, generated by Google Authenticator, Authy, or any other password manager out there.

Back to your process: you don't need 2 timestamp fields. It's trivial to calculate time + 5min on any language you use, so adding it twice is superfluous. Just createdTimestamp is enough.

An usability note: your users will not like to have to enter SMS codes every time their login expires for any reason. You could ask for the SMS when they first log, and toggle the userConfirmed flag somewhere. You know an user is trusted when they sent the first 2FA token, no need to ask them again and again. Ask again when they buy more than 2 or 3 gift cards, or redeem more than a few.

  • 1
    Thanks! All good points which im going to implement
    – Mark
    Jan 17, 2019 at 15:22
  • btw, regarding they last point, we ask for SMS code each time as we're protecting in case someone somehow gets hold of the link to their gift card...
    – Mark
    Jan 18, 2019 at 14:06
  • 2
    @Mark then ask for SMS code when redeeming the card, not for logging-in every time, or browsing the cards, or anything. Ask 2FA only for state change operations, so people will be secured and not bothered.
    – ThoriumBR
    Jan 18, 2019 at 15:26

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .