Skip to content

Log in a new device without typing a password #252

Description

@TimoPtr

Problem statement

Once a client knows the server URL (from mDNS, a typed URL), the user still has to log in. Today that always means typing a username and password (and a 2FA code if enabled) into the Home Assistant login page, on the new device.

This is where onboarding hurts most:

  • Constrained devices. A car display, a TV with a remote, a watch or a wall tablet. Typing a strong password there is slow and error-prone.
  • Some devices can't show the login page. Some clients can't show a WebView at all.
  • Many users don't know their password. Often the admin created the account and set the password for them. Or they use a password manager that only lives on their phone.
  • Every new device repeats it. Users with a phone, a tablet, a car and a TV type their credentials four times, while they're already logged in on at least one of them.

Who is impacted: every Home Assistant user adding a client, and most of all household members who didn't set up Home Assistant themselves.

Why it matters to OHF: logging in is the second step of every onboarding, right after finding the server. Letting an already logged-in device vouch for a new one ("Scan this code to log in") is what people know from Netflix or WhatsApp Web. It makes Home Assistant easier for the whole household without weakening security, and without any cloud service: everything happens between the devices and the user's own server.

Community signals

Came from internal thinking: the onboarding proposal document, and the "Simplify onboarding" session at the OHF Summit 2026. That session also noted that at the Summit itself, everyone had to log in to a shared generic account to create their own.

Scope & Boundaries

In scope

One core mechanism: a pending login request that an already logged-in session approves. The QR code can go either way:

  1. The new device shows a code and a QR code (OAuth 2.0 Device Authorization Grant, RFC 8628).
    • The user approves it from any logged-in session: the Companion app scans the QR, or they type the code in a browser.
    • This also covers a desktop without a camera: the desktop browser shows the QR code, and the phone scans it.
  2. A logged-in device shows a QR code.
    • A logged-in session (desktop or phone) shows a "Log in a new device" QR code with the server URL and a one-time, short-lived code.
    • The new device scans it from onboarding and is logged in.
    • This extends today's invite link (my.home-assistant.io/invite/#url=), which only carries the URL.

Which account. By default, the new device is logged in as the user who approves or shows the QR code. No extra step is needed.

Important

We could have a variant where we send the QR code content of 2 that contains the secret over the device in a secure manner so we don't need OAuth device flow.

Admin variant, with consent.

  • An admin can choose another existing user instead.
  • The request then waits for that user's consent through a notification to the user: Home Assistant sends them "Allow Car to log in as you?" with Approve and Deny, on their logged-in Companion apps.
  • The new device is only logged in once they approve.

Important

We might drop the admin variant by only allowing a the invite flow where the user will have to set a password on the account for security/privacy reason.

Also in scope:

  • The frontend page to approve a request: device name, type, where it's connecting from, the account (with a user picker for admins), and Approve / Deny.
  • The Companion app on both sides: showing the code and QR code, or scanning one; showing the QR code for a new device; handling the consent notification.
  • Gated on the Home Assistant core version, falling back to today's login page.

Not in scope

  • Logging a device in as another user without their consent. The admin variant always needs the user's approval.
  • Invitations for new users (the admin shares a QR code, and the person creates their own account and password). This is closely related and uses the same mechanism, but it's its own opportunity.
  • Passwordless accounts, application passwords, and roles or permission changes.
  • Sending credentials or tokens over BLE (that needs bonding and encryption; see the BLE discovery opportunity).
  • Installing mTLS client certificates on the new device.
  • Changing how existing sessions and refresh tokens work.

Foreseen solution

Important

Everything bellow has been generated by AI from a transcript of the summit talk and from the document, it requires
alignment between all the actors.

Potential draft of Oauth device flow
 1. QR on the new device                     2. QR on a logged-in device           Admin variant: consent

 New device          Logged-in session       Logged-in session    New device       Other user's phone
 ┌──────────────┐    ┌──────────────────┐    ┌─────────────────┐ ┌─────────────┐   ┌──────────────────────┐
 │ Code WDJB-MJ │    │ Scan QR / type   │    │ Log in a new    │ │ Scan QR     │   │ Allow "Car" to log   │
 │ [QR]         │ ─▶ │ code on /auth/   │    │ device [QR]     │▶│ from        │   │ in as you?           │
 │ polling...   │    │ device           │    │ (expires in 5m) │ │ onboarding  │   │ (asked by admin Sam) │
 │ ✓ logged in  │ ◀─ │ As: [me ▾]       │    │ As: [me ▾]      │ │ ✓ logged in │   │ [Approve] [Deny]     │
 └──────────────┘    │ [Approve] [Deny] │    └─────────────────┘ └─────────────┘   └──────────────────────┘
                     └──────────────────┘
        "As" is always yourself, except for admins; choosing another user adds the consent step
        both directions end in /auth/token returning normal tokens

Home Assistant core (auth)

  • Pending login requests.
    • Created by a new unauthenticated endpoint, POST /auth/device (RFC 8628 device authorization endpoint). It takes the client_id (same IndieAuth client ids as today, e.g. https://home-assistant.io/android), a device name and a device type.
    • It returns a device_code, a short user_code, a verification_uri and verification_uri_complete, and an expires_in of about 10 minutes.
    • Requests are kept in memory, are single-use, and are rate limited per IP.
  • Token grant. /auth/token accepts grant_type=urn:ietf:params:oauth:grant-type:device_code.
    • While the request is pending (including while it waits for consent), it answers authorization_pending or slow_down.
    • After approval, it returns a normal access and refresh token for the chosen user, created for that client_id, exactly like the authorization code flow does today.
    • If the request was denied or expired, it answers access_denied or expired_token.
  • Approval. New WebSocket commands for authenticated sessions:
    • get a pending request by user_code, for the approval screen;
    • approve or deny it, for yourself, or for another user if you're an admin.
  • QR on a logged-in device (direction 2). A WebSocket command lets an authenticated session create an already-approved, single-use request, valid for a few minutes. The QR code encodes the server URL and the device_code. The new device scans it, then exchanges the code at /auth/token like in direction 1.
  • Consent (admin variant). When an admin approves or creates a request for another user, the request becomes "waiting for consent".
    • Core notifies that user through mobile_app on their registered devices. The notification has Approve and Deny actions with authenticationRequired, so the phone has to be unlocked. This option already exists for notification actions in the Android app.
    • The answer goes through the phone's own authenticated connection, not through a generic event.
    • It also shows up in the frontend for that user, so they can answer from any logged-in session.
  • Discovery. Add device_authorization_endpoint and the device code grant type to /.well-known/oauth-authorization-server, which already lists the other endpoints. Clients can then detect support without a version check.

Frontend

  • /auth/device approval page (the verification_uri). It prefills user_code from verification_uri_complete and shows the device name, type, client and approximate origin (IP). It shows the account (yourself, or a user picker for admins) and Approve and Deny.
  • "Log in a new device" in the user profile, showing the direction 2 QR code with a countdown (and the same user picker for admins).
  • "Log in with another device" on the login page, as an alternative to the password form. It starts direction 1 for browsers too.
  • A consent prompt for users who have a request waiting for them.

Companion app

  • As the new device.
    • After the server is found, the connection screen offers "Log in with another device" next to the usual login. It shows the code, the QR code and the verification URL, polls /auth/token at the given interval, then continues onboarding as after a normal login.
    • "Scan a QR code" on the first onboarding screen, for direction 2. It reuses the invite link handling, which today only fills in the URL.
  • As the logged-in device.
    • It scans direction 1 QR codes (with the existing barcode scanner) and opens the approval page.
    • It shows the direction 2 QR code from settings.
    • It shows the consent notification, acting directly from it or opening the approval screen.

Risks & open questions

  1. Admin variant: is consent enough? This is the proposed answer to the Summit discussion, which had no agreement.
    • Arguments for letting admins do it: admins already have full control, and many household members are happy that the admin sets up their devices.
    • Arguments against: a device shouldn't be logged in as someone without them knowing.
  2. Unauthenticated endpoint. POST /auth/device must not become a way to fill memory: cap the number of pending requests and rate limit.
  3. Direction 2 QR leakage. The QR code is a bearer secret for a few minutes: whoever scans it first gets logged in. Keep it short-lived and single-use, show it only on request, and notify the user when it has been used.
  4. Which user the device belongs to. In the Companion app, a device is registered to the user who logged in. The Summit asked whether a device (a car, a TV) should belong to a person at all, or be a "device user". Out of scope here, but the mechanism shouldn't block it later.

Appetite

No response

Execution issues

No response

Decision log

Date Decision Outcome

Activity

  1. edenhaus commented on Sep 30, 2026

    @edenhaus
    Member

    In my opinion we should put Admin variant, with consent. out of scope for this proposal and if we really want it create a dedicated proposal for it. It adds a lot of complexity, where we need to get the approval from the other user and co including a lot of edge cases which need to be handled. In my opinion the user should use the phone of the other person in first place and so we can skip this complex use-case. Also keep in mind that users not often onboard new devices.

    Also this proposal is missing the discussed alternative (in Lisbon) for point 1: Use a similar approach as currently opendisplay.org does with their display. Where the user scans the provided QR code which includes a key to communicate securely over BLE (or what ever). In my opinion this has the advantage as we could just create an access token on the phone and send it over. With this approach we could also send over the certificates used for mTLS in case HA is just reachable with mTLS, which is a open question in #251

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Labels

No labels
No labels

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions