-
-
Notifications
You must be signed in to change notification settings - Fork 58
How to implement your own QR Code provider
This library comes with three 'built-in' QR-code providers. Some TwoFactorAuth
constructor overloads accept an IQrCodeProvider
argument which lets you specify a built-in or custom QR-code provider. All three built-in providers do a simple HTTP request to retrieve an image using a WebClient
and implement the IQrCodeProvider
interface which is all you need to implement to write your own QR-code provider.
The default provider is the ImageChartsQrCodeProvider
which uses the image-charts.com drop-in replacement for Google Chart Tools to render QR-codes. Then we have the QrServerQrCodeProvider
which uses the goqr.me API and finally we have the QRicketQrCodeProvider
which uses the QRickit API. All three inherit from a common (abstract) baseclass BaseHttpQrCodeProvider
because all three share the same functionality: retrieve an image from a 3rd party over HTTP. All three classes have constructors that allow you to tweak some settings and most, if not all, arguments should speak for themselves. If you're not sure which values are supported, click the links in this paragraph for documentation on the API's that are utilized by these classes.
If you don't like any of the built-in classes, because you don't want to, or can't, rely on external resources for example, or because you're paranoid about sending the TOTP secret to these 3rd parties (which is useless to them since they miss at least one other factor in the MFA process), feel tree to implement your own. The IQrCodeProvider
interface couldn't be any simpler. All you need to do is implement 2 methods:
byte[] GetQrCodeImage(string text, int size);
string GetMimeType();
The GetMimeType()
method should return the MIME type of the image that is returned by our implementation of GetQrCodeImage(string text, int size)
. In this example it's simply image/png
. The GetQrCodeImage()
method is passed two arguments: text
and size
. The latter, size
, is simply the width/height in pixels of the image desired by the caller. The first, text
is the text that should be encoded in the QR code. An example of such a text would be:
otpauth://totp/LABEL:alice@google.com?secret=XANIK3POC23RCRYN&issuer=ISSUER
All you need to do is return the QR code as binary image data and you're done. All parts of the text
have been escaped for you (but note: you may need to escape the entire text
just once more when passing the data to another server as GET-parameter).
Let's try implementing our own!
- Create a class
MyQRProvider.cs
using System;
namespace MyNameSpace
{
public class MyQRProvider
{
}
}
- Implement the
IQrCodeProvider
interface:
using System;
using TwoFactorAuthNet.Providers.Qr;
namespace MyNameSpace
{
public class MyQRProvider : IQrCodeProvider
{
}
}
- To install QrCode.Net, run the following command in the Package Manager Console
PM> Install-Package QrCode.Net
NOTE: Explaining the actual process of generating a QR code is far beyond the scope of this document, so for that we'll use QrCode.Net in this example. However, it is up to you to find a library that suits your needs and demands (or write your own QR code generator if you're up for it!) if you don't like QrCode.Net.
- Implement the
IQrCodeProvider
interface members:
using Gma.QrCodeNet.Encoding;
using Gma.QrCodeNet.Encoding.Windows.Render;
using System.Drawing.Imaging;
using System.IO;
using TwoFactorAuthNet.Providers.Qr;
namespace MyNameSpace
{
public class MyQRProvider : IQrCodeProvider
{
public string GetMimeType()
{
return "image/png";
}
public byte[] GetQrCodeImage(string text, int size)
{
var encoder = new QrEncoder();
var qrCode = encoder.Encode(text);
var renderer = new GraphicsRenderer(new FixedCodeSize(size, QuietZoneModules.Two));
byte[] result;
using (var stream = new MemoryStream())
{
renderer.WriteToStream(qrCode.Matrix, ImageFormat.Png, stream);
result = stream.ToArray();
}
return result;
}
}
}
Note that this library does not require an external 3rd party and the QR code generation is handled by the QrCode.Net library. This way we don't need (outgoing) internet access and the shared secret is only known by you. No more external dependencies, no more unnecessary latencies.
- Pass your newly created QR code provider to a TwoFactorAuth constructor overload that accepts an
IQrCodeProvider
argument.
var tfa = new TwoFactorAuth("MyCompany", new MyQRProvider());
From here on the tfa
instance will use your QR code provider.