Cheesecake Labs Builds SMS User Verification With Python and Django

December 19, 2016
Written by

cheesecakelabs

Cheesecake Labs, a development shop, built their SMS user verification app in less than a day using Python and Django. Here’s how it works from the user’s end.

1. The user enters his/her phone number in the app

2. The app pings the server, and the user quickly receives an SMS with a confirmation 6-digit pin-code.

3. As soon as the user types the correct pin in the app, the phone number is validated.

This was iOS developer, Marcelo Salloum‘s first Twilio hack. Marcello wanted to create a verification feature that didn’t require the users to create a log-in and password. Instead, he used the username everyone has in their pocket at all times — your phone number.

Here’s the code he used to build the feature, which Marcello based off of these docs.

Cheesecake Lab’s SMS Verification Solution — Built With Python + Django

When a new user signs up, a http request is triggered through @receiver(user_signed_up), then the SMSVerification model creates a pin code for that user and sends it to the user’s phone.

class SMSVerification(TimestampedModel):
    user = models.ForeignKey(User)
    verified = models.BooleanField(default=False)
    pin = RandomPinField(length=6)
    sent = models.BooleanField(default=False)
    phone = PhoneNumberField(null=False, blank=False)

    def send_confirmation(self):

        logger.debug('Sending PIN %s to phone %s' % (self.pin, self.phone))

        if phonenumbers.is_valid_number(self.phone):
            if all([settings.TWILIO_ACCOUNT_SID, settings.TWILIO_AUTH_TOKEN, settings.TWILIO_FROM_NUMBER]):
                try:
                    twilio_client = TwilioRestClient(settings.TWILIO_ACCOUNT_SID, settings.TWILIO_AUTH_TOKEN)
                    twilio_client.messages.create(
                        body="Your forgeter activation code is %s" % self.pin,
                        to=str(self.user.userprofile.phone),
                        from_=settings.TWILIO_FROM_NUMBER
                    )
                    self.sent = True
                    self.save()
                    return True
                except TwilioException, e:
                    logger.error(e)
            else:
                logger.warning('Twilio credentials are not set')
        return False

    def confirm(self, pin):
        if self.pin == pin:
            self.user.auth_token.delete()
            self.user.auth_token = TokenModel.objects.create(user=self.user)
            self.verified = True
            self.save()

        return self.verified


@receiver(user_signed_up)
def send_sms_verification(request, user, **kwargs):
    verification = SMSVerification.objects.create(user=user, phone=user.userprofile.phone)
    verification.send_confirmation()

In the case where the user asks for another SMS, Cheesecake Labs sends ReSend logic:

class ResendView(GenericAPIView):
    permission_classes = (AllowAny,)
    allowed_methods = ('POST',)

    def resend_or_create(self):
        phone = self.request.data.get('phone')
        send_new = self.request.data.get('new')
        sms_verification = None

        user = User.objects.filter(userprofile__phone=phone).first()

        if not send_new:
            sms_verification = SMSVerification.objects.filter(user=user, verified=False) \
                .order_by('-created_at').first()

        if sms_verification is None:
            sms_verification = SMSVerification.objects.create(user=user, phone=phone)

        return sms_verification.send_confirmation()

    def post(self, request, *args, **kwargs):
        success = self.resend_or_create()

        return Response(dict(success=success), status=status.HTTP_200_OK)

That’s all the code it takes to build User Verification. Check out a tutorial on how to build it here.