ยท hands on

Reading TOTP Data for 2FA from QR Code in TypeScript

Learn how to extract Time-based One-Time Password (TOTP) data from a QR code in TypeScript using sharp and jsQR.

Two-Factor Authentication (2FA) using Time-based One-Time Passwords (TOTP) enhances security by requiring a second form of authentication. A common method to set up TOTP is by scanning a QR code containing the TOTP URI. In this tutorial, we'll demonstrate how to read TOTP data from a QR code in TypeScript using sharp and jsQR.

Contents

Setting Up Your Environment

Before we begin, ensure you have Node.js installed. You can set up a new TypeScript project or use an existing one. We'll need to install a few libraries:

npm install typescript @types/node sharp jsqr

These libraries serve the following purposes:

  • sharp: For loading images like our QR code for 2FA.
  • jsqr: To extract plaintext from the QR code image.

We use sharp instead of Jimp as Jimp does not support SVG image types at the time of writing.

Source Code

Here's the complete code to read TOTP data from a QR code stored in an SVG file:

import jsQR from 'jsqr';
import sharp from 'sharp';
 
const svgFile = './src/download.svg';
 
// Get raw pixel data in RGBA format
const { data, info } = await sharp(svgFile).ensureAlpha().raw().toBuffer({ resolveWithObject: true });
const rgbaValues = new Uint8ClampedArray(data.buffer);
 
// Log the string version of the QR code data
const code = jsQR.default(rgbaValues, info.width, info.height);
console.log(code?.data);

Using sharp we can read the raw image data while ensuring the addition of an alpha/transparency channel to ensure an RGBA color model.

By constructing a Uint8ClampedArray, we generate binary data representing RGBA pixel values structured as [r0, g0, b0, a0, r1, g1, b1, a1, ...]. This pixel data is then processed by jsQR to extract the QR code information.

For GitHub's two-factor authentication, the QR code data for use with a TOTP app will look as follows:

otpauth://totp/GitHub:username?secret=TOPSECRET&issuer=GitHub

Back to Blog