Django OTP TOTP - how to display QR code in template

Viewed 432

I have successfully implemented two-factor-auth package to my web app however I would like to display QR code to a template when a user is logged in but am unable to do so as it stands.

This package uses wizard forms and when a user is prompted to setup two factor the QR code is displayed during setup for them to scan on their chosen device but not sure how to use the QR code for later use in another template.

I found the follwing piece of code from the wizard template which I tried to use but says page not found:

      <div class="d-flex justify-content-center">
    <p><img src="{{ QR_URL }}" alt="QR Code" /></p>
     </div>

Page not found error

 Using the URLconf defined in wfi_workflow.urls, Django tried these URL patterns, in this order:

    admin/
    account/login/ [name='login']
    account/two_factor/setup/ [name='setup']
    account/two_factor/qrcode/ [name='qr']

The current path, account/two_factor/qrcode/, matched the last one. 

But I can view the QR code for users via Admin panel under:

  • Otp_Totp
  • TOTP devices
  • Click on user and QRCode link is at the bottom of page

Anyone know how to go about displaying the QR code only in another template? If more info is required do let me know. Thanks

2 Answers

To display QR code in template, you can get the image url in view like this:

device = TOTPDevice.objects.get(user=obj)
if device:
    qr_code_url = reverse('admin:%s_%s_qrcode' % (TOTPDevice._meta.app_label, TOTPDevice._meta.model_name), args=[device.pk])

or directly svg image:

device = TOTPDevice.objects.get(user=obj)
if device:
    import qrcode
    import qrcode.image.svg
    img = qrcode.make(device.config_url, image_factory=qrcode.image.svg.SvgImage)

To incorporate the QR code into a template, you need to create it as a base 64-encoded image and pass it to your template in the context data:

views.py

import qrcode
from io import BytesIO
from base64 import b64encode

qr_code_img = qrcode.make(device.config_url)  # This should be the device for which you want to generate the QR code
buffer = BytesIO()
qr_code_img.save(buffer)
buffer.seek(0)
encoded_img = b64encode(buffer.read()).decode()
qr_code_data = f'data:image/png;base64,{encoded_img}'

return render(request, 'template.html', {'qr_code_data': qr_code_data})

template.html

<img src="{{ qr_code_data }}" />
Related