Repository navigation
Description
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:
- 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.
- 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 theclient_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 shortuser_code, averification_uriandverification_uri_complete, and anexpires_inof about 10 minutes. - Requests are kept in memory, are single-use, and are rate limited per IP.
- Created by a new unauthenticated endpoint,
- Token grant.
/auth/tokenacceptsgrant_type=urn:ietf:params:oauth:grant-type:device_code.- While the request is pending (including while it waits for consent), it answers
authorization_pendingorslow_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_deniedorexpired_token.
- While the request is pending (including while it waits for consent), it answers
- 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.
- get a pending request by
- 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/tokenlike 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_appon their registered devices. The notification has Approve and Deny actions withauthenticationRequired, 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.
- Core notifies that user through
- Discovery. Add
device_authorization_endpointand 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/deviceapproval page (theverification_uri). It prefillsuser_codefromverification_uri_completeand 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/tokenat 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.
- 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
- 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
- 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.
- Unauthenticated endpoint.
POST /auth/devicemust not become a way to fill memory: cap the number of pending requests and rate limit. - 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.
- 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
edenhaus commentedon Sep 30, 2026
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