Skip to main content

Overview

The Nest protocol uses HTTP Basic Authentication on every request. The device embeds its serial number in the user ID field, allowing the server to identify any device from any request.
This page covers device-level authentication on the Device Protocol API (port 8000). For the Control API (port 8082), see API Authentication.

HTTP Basic Auth

Every subscribe, PUT, and entry request includes:
Authorization: Basic <base64(userid:password)>
The user ID follows the format d.{SERIAL}.{suffix}:
Authorization: Basic <base64("d.09AA01AB12345678.BC7C9039:password")>
                                 ^^^^^^^^^^^^^^^^^
                                 serial number extracted here
To identify the device, decode the Base64 value and extract the second dot-delimited segment.

Identity header fallback

Some non-production firmware configurations send X-nl-client-id or X-nl-device-id headers instead of Basic Auth. On production firmware, Basic Auth is always present. Handle headers as fallback only:
HeaderFormatWhen sent
Authorization: Basicbase64(d.{SERIAL}.{suffix}:pass)Always (production firmware)
X-nl-client-idd.{SERIAL}.{suffix}Non-production only
X-nl-device-id{SERIAL} (bare serial)Non-production only, entry requests

Credential Provisioning

The server can provision new credentials to the device by including X-nl-set-client-credentials in any 200 response:
X-nl-set-client-credentials: userid password
The device stores these and uses them for subsequent requests.
Do not provision credentials via 401 responses. This can cause a credential loop on some firmware versions: the device receives new credentials, falls back to defaults before using them, gets another 401, receives credentials again — indefinitely.If you provision credentials, do it only in 200 responses.
The NLE self-hosted server skips credential provisioning entirely:
  1. Accept all subscribe and PUT requests regardless of password
  2. Parse the device serial from the Basic Auth user ID
  3. Look up the device in the database by serial
This avoids credential management complexity and the loop described above.

Entry Key (Pairing Code)

During device setup, users must enter a code displayed on the thermostat to claim it. The device fetches this code from the passphrase_url returned by /nest/entry.

Request

GET /nest/passphrase HTTP/1.1
Authorization: Basic <base64(d.SERIAL.SUFFIX:password)>

Response

{
  "value": "A3XR7M2",
  "expires": 1707234600000
}
FieldTypeNotes
valuestring7-character alphanumeric code
expiresnumberMilliseconds since epoch — must be a JSON number, not a string
If expires is a JSON string (e.g., "1707234600000" with quotes), the device silently rejects the response and never displays the entry code. Use a number literal.
The device displays the code in XXX-XXXX format (e.g., A3X-R7M2). The expiration must be at least 30 minutes in the future. The server returns the same unexpired key on repeated calls — generating a new key on each poll would invalidate the code before the user can enter it.

Pairing Completion

After the user enters the entry code, the server completes pairing by pushing two buckets to the device on its open subscribe connection: 1. User bucket — triggers pairing on the device:
{
  "object_revision": 1,
  "object_timestamp": 1707148800000,
  "object_key": "user.homeassistant",
  "value": { "name": "homeassistant" }
}
The name field is what triggers pairing completion internally. Without it, the setup screen remains visible. 2. Structure bucket — establishes the device-home association:
{
  "object_revision": 1,
  "object_timestamp": 1707148800000,
  "object_key": "structure.default",
  "value": {
    "name": "Home",
    "devices": ["09AA01AB12345678"]
  }
}
Include both the user bucket and structure bucket on every subscribe reconnection for paired devices — not just at registration time. If the server restarts or the device reboots, the device re-registers and needs these buckets to restore pairing state.