Skip to content

Add QR device-handoff login ("scan to sign in") - #630

Merged
ddon merged 3 commits into
BeamLabEU:mainfrom
alexdont:main
Jul 12, 2026
Merged

Add QR device-handoff login ("scan to sign in")#630
ddon merged 3 commits into
BeamLabEU:mainfrom
alexdont:main

Conversation

@alexdont

Copy link
Copy Markdown
Contributor

What

Adds a QR "scan to sign in" flow to the login page, integrating the new keyfob library (0.1.0).

A signed-out browser shows a QR code; an already-signed-in phone scans it (the native camera works — no app needed), reviews the requesting device (browser / OS / IP), and taps Approve — the desktop signs in with no password. Approval always happens on the trusted phone; the desktop receives nothing until the phone approves (defense against QR-jacking is keyfob's confirm-screen + secret split).

How

  • PhoenixKit.Users.QrLogin context — wraps keyfob on the internal PubSub (:phoenix_kit_internal_pubsub), reads the qr_login_enabled setting, extracts device metadata for the confirm screen, and logs a user.qr_login_approved activity on approval.
  • Desktop QR page (public LV, /users/qr-login) — mints the request on connect, renders keyfob's panel, redirects to completion on approval, and flips to "show a new code" when the 2-min TTL lapses (token-keyed timer so refresh/approve races can't clobber state).
  • Phone confirm page (authenticated LV, /users/qr-login/scan/:token) — device review + Approve/Deny; approves on behalf of the signed-in user. Unauthenticated hits are redirected to login with return_to preserved, then bounced back.
  • Completion controller (/users/qr-login/finish/:token) — Keyfob.consume/1log_in_user.
  • Routes (localized + non-localized), Keyfob.Store.ETS in the supervisor, qr_login_enabled setting (default off), a toggle in Authorization settings, a "Sign in with QR code" button on the login page (gated on the setting), and a new icon_qr_code.
  • Extracted new gettext strings across all 8 locales.

Enabling / testing

Off by default. Enable at Admin → Settings → Authorization → QR Code → "Enable QR code sign-in"; the login-page button then appears. The QR encodes an absolute Routes.url link, so the phone must be able to reach the host (real domain in prod; a LAN IP / tunnel for local dev).

Notes

  • Requires keyfob ~> 0.1 (published to Hex).
  • Verified: mix compile --warnings-as-errors, mix credo --strict, mix format --check-formatted clean; routes confirmed via mix phx.routes.

🤖 Generated with Claude Code

Alexander Donand others added 3 commits July 12, 2026 22:03
Integrate the keyfob library as PhoenixKit's QR sign-in flow: a signed-out
browser shows a QR code, an already-signed-in phone scans it (native camera
works), reviews the requesting device, and taps Approve — the desktop signs
in with no password. Approval always happens on the trusted phone; the
desktop receives nothing until the phone approves.
- PhoenixKit.Users.QrLogin context wraps keyfob on the internal PubSub,
reads the qr_login_enabled setting, extracts device metadata, and logs a
user.qr_login_approved activity on approval.
- Desktop QR page (public LV), phone confirm page (authenticated LV), and
completion controller (consume -> log_in_user). Panel expires with the
request TTL and offers a fresh code.
- Routes (localized + non-localized), Keyfob.Store.ETS in the supervisor,
qr_login_enabled setting default (off), Authorization-settings toggle,
a "Sign in with QR code" button on the login page, and an icon_qr_code.
- Extract new gettext strings across all locales.
Requires keyfob ~> 0.1.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01MsjUy1HnuJnCSrqdbnANYL
# Conflicts:
#	priv/gettext/de/LC_MESSAGES/default.po
#	priv/gettext/default.pot
#	priv/gettext/en/LC_MESSAGES/default.po
#	priv/gettext/es/LC_MESSAGES/default.po
#	priv/gettext/et/LC_MESSAGES/default.po
#	priv/gettext/fr/LC_MESSAGES/default.po
#	priv/gettext/it/LC_MESSAGES/default.po
#	priv/gettext/pl/LC_MESSAGES/default.po
#	priv/gettext/ru/LC_MESSAGES/default.po
@ddon
ddon merged commit 0da5216 into BeamLabEU:mainJul 12, 2026
ddon pushed a commit that referenced this pull request Jul 12, 2026
Review of the QR device-handoff login (#630) and prefix-hardening (#631)
PRs surfaced real gaps: the qr_login_enabled setting wasn't an immediate
kill switch on the phone-approval/completion paths, the public QR mint
endpoint had no rate limiting, and V26's pgcrypto digest() backfill and
the new Oban prefix-detection regex both had the same class of bugs the
prefix-hardening PR was written to fix elsewhere. See CLAUDE_REVIEW.md
in each PR's dev_docs directory for full findings.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants

@alexdont@ddon