The authenticator QR is black on nothing, which is nothing on a dark page #87

Closed
opened 2026-09-07 14:03:05 +00:00 by tiagoagueda · 0 comments
Owner

Observation

when setting up TOTP, on a dark theme, the QR code is unreadable, invert the colors in
this case so the qr code in white (and not in black with white border)

What is wrong

allauth builds the QR with qrcode's SvgPathImage factory. Generated and looked at rather
than assumed, the whole image is:

<svg width="33mm" height="33mm" viewBox="0 0 33 33" ...><path d="M4,4H5V5H4z…" fill="#000000"/></svg>

One path, filled #000000, and no background whatsoever — not even a white quiet zone.
The only colour anywhere in the file is black.

On a light page that reads perfectly, which is why it shipped. On a dark page it is black on
near-black: not low contrast, invisible. No camera will find it, and nor will a person.

Setting up two-factor authentication is not a page anybody visits twice, so it is exactly
the kind of screen that goes years without being looked at in both themes.

The fix

Tag the image and invert it in the dark theme only:

.qr-code {
  @variant dark { filter: invert(1); }
}

A filter works on the colour channels and leaves alpha alone, so the modules flip to white
and the transparency stays transparent — the quiet zone becomes the page's own dark, which
is what a scanner wants: an unbroken margin of one colour that contrasts with the modules.

The class is attached through allauth's element system, which already tags this image
mfa,totp,qr, so no other image is affected — an avatar rendered through the same element
template is untouched, and there is a test saying so.

Worth knowing: an inverted QR is not universally scannable

The symbology specification allows a reader to handle reflectance reversal, and modern phone
cameras generally do. Some older or simpler scanners do not, and expect dark modules on a
light field.

Left as asked, for two reasons. The alternative — a white plate behind the code in both
themes — is reliably scannable but puts a stark white card in the middle of a dark page,
which is the thing being complained about. And the failure is recoverable: the same page
shows the secret as text directly beneath the code, so anybody whose scanner refuses can
type it.

If a real scanner turns out to refuse it, the white plate is a one-line change.

Classification

Bug, accessibility. Present since the dark theme existed.

## Observation > when setting up TOTP, on a dark theme, the QR code is unreadable, invert the colors in > this case so the qr code in white (and not in black with white border) ## What is wrong allauth builds the QR with `qrcode`'s `SvgPathImage` factory. Generated and looked at rather than assumed, the whole image is: ```xml <svg width="33mm" height="33mm" viewBox="0 0 33 33" ...><path d="M4,4H5V5H4z…" fill="#000000"/></svg> ``` One path, filled `#000000`, and **no background whatsoever** — not even a white quiet zone. The only colour anywhere in the file is black. On a light page that reads perfectly, which is why it shipped. On a dark page it is black on near-black: not low contrast, *invisible*. No camera will find it, and nor will a person. Setting up two-factor authentication is not a page anybody visits twice, so it is exactly the kind of screen that goes years without being looked at in both themes. ## The fix Tag the image and invert it in the dark theme only: ```css .qr-code { @variant dark { filter: invert(1); } } ``` A filter works on the colour channels and leaves alpha alone, so the modules flip to white and the transparency stays transparent — the quiet zone becomes the page's own dark, which is what a scanner wants: an unbroken margin of one colour that contrasts with the modules. The class is attached through allauth's element system, which already tags this image `mfa,totp,qr`, so no other image is affected — an avatar rendered through the same element template is untouched, and there is a test saying so. ## Worth knowing: an inverted QR is not universally scannable The symbology specification allows a reader to handle reflectance reversal, and modern phone cameras generally do. Some older or simpler scanners do not, and expect dark modules on a light field. Left as asked, for two reasons. The alternative — a white plate behind the code in both themes — is reliably scannable but puts a stark white card in the middle of a dark page, which is the thing being complained about. And the failure is recoverable: the same page shows the secret as text directly beneath the code, so anybody whose scanner refuses can type it. If a real scanner turns out to refuse it, the white plate is a one-line change. ## Classification Bug, accessibility. Present since the dark theme existed.
tiagoagueda added this to the 0.3.0 milestone 2026-09-07 14:03:05 +00:00
Sign in to join this conversation.
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference
Postulo/postulo#87
No description provided.