It is tempting to trust a device because it appeared on the local network. The service has a friendly name, the client can connect, and the network is nearby. That feels like enough.
It is not. Discovery answers, "What endpoint should I try?" Enrollment answers, "Which system is this, what access will this device receive, and how can that access be removed?" Recent work on palOMine's native LAN client has been about keeping those questions separate.
What does local discovery actually prove?
Very little, by design. A local discovery protocol reports that a service with a particular name and protocol is reachable at an address and port. That is useful: it removes address entry, a local inventory, and a registry for systems that only need to work on one link.
It does not prove that the responder is the intended host, that another participant did not advertise the same service, or that this client should receive access.
That is not a flaw in discovery. It is its boundary. As mDNS is for one link explains, cooperative local naming is useful precisely because it does not require an authority. The mistake is asking it to become one after the fact.
Discovery provides a candidate. Trust requires a separate decision.
What must enrollment prove instead?
Enrollment establishes three facts. The client proves possession of the one-time enrollment material, bound to a fresh challenge so it cannot be replayed. The host returns its trust material only after that proof succeeds, encrypted to an ephemeral client key. The operator then reviews the host, fingerprint, and expiry before a durable credential exists.
The cryptography is specialized, but the protocol shape is simple:
candidate = discover_on_local_link()
challenge = candidate.begin_enrollment()
ephemeral_key = generate_recipient_key()
proof = prove(enrollment_secret, challenge, ephemeral_key.public)
encrypted_bundle = candidate.complete_enrollment(proof, ephemeral_key.public)
bundle = decrypt(encrypted_bundle, ephemeral_key.private)
review(bundle.host, bundle.ca_fingerprint, bundle.expiry)
require_explicit_operator_confirmation()
credential = exchange_once_over_pinned_tls(bundle.capability)
store_only(credential)
Not every local system needs this exact sequence. What matters is the boundary: finding an endpoint, proving eligibility, verifying identity, gaining consent, and issuing access are separate steps.
Why is the bootstrap listener so narrow?
Bootstrapping trust sometimes requires a temporary plaintext path. That does not justify exposing the control plane without its normal protections.
The bootstrap listener accepts only the enrollment exchange. It has no ordinary API routes, voice endpoint, control credentials, or reusable certificate download. Before proof succeeds it returns public challenge data. Afterwards, it returns only the encrypted bundle for the ephemeral key bound into that proof.
It is a bridge to the pinned path, not a second way to operate the system.
sequenceDiagram
participant C as Native client
participant D as Local discovery
participant B as Narrow bootstrap listener
participant H as Pinned host API
participant S as Credential store
C->>D: Find candidate host
D-->>C: Host name and endpoint
C->>B: Fresh challenge request
B-->>C: One-time challenge
C->>B: Proof bound to ephemeral recipient key
B-->>C: Encrypted host and trust bundle
C->>C: Decrypt, validate, and show review
C->>H: Confirmed one-time credential exchange over pinned TLS
H-->>C: Per-client credential
C->>S: Store credential only
The asymmetry matters. Discovery and bootstrap may be convenient; durable authority starts only after review and a pinned connection.
Why show a fingerprint to a human?
Security flows often hide their only meaningful decision behind a button labeled "Continue." A useful review instead shows the host, fingerprint, and pending expiry. The operator can compare those values with the intended host before the client gains access.
The verified trust root stays in the client's TLS configuration; the flow does not install a root certificate into the operating system or browser. That limits trust to this client and this host. It also makes rotation explicit: when the trust root changes, prior credentials stop working rather than silently trusting a different identity.
What becomes durable after pairing?
Only the issued, revocable client credential becomes durable. The enrollment secret, challenge, proof, temporary private key, and a broad operating-system trust exception do not.
The host retains a verification form and revocation state; the client stores the credential in the platform credential store. The host can revoke a device, and a device can revoke only itself. Losing one laptop does not require rotating every client, and removing one client cannot remove another.
This is least privilege applied to device identity. A paired client can call the host as itself. It does not receive the operator's bearer token or authority over other clients.
What should fail closed?
The successful demo is not the important test. Enrollment must refuse to issue access for an expired or reused challenge, invalid proof, substituted recipient key, changed fingerprint, malformed bundle, or revoked credential.
Local credential storage is another failure boundary. If the host issues a credential and the platform store rejects it, the host now knows a client that cannot connect or remove itself. The client should check its non-secret storage path before exchange and report storage failures separately from protocol failures.
Enrollment is a state transition across two machines and a local security boundary. The implementation should leave no durable access behind unless that transition completes.
The better mental model
Treat local discovery as a routing hint. Treat enrollment as a constrained trust flow. Treat the resulting credential as a revocable, least-privilege relationship with one host.
That is more deliberate than "select a device and connect," but it leaves a system that can explain what was trusted, what failed, and how access is removed.
Previous: mDNS Is for One Link
Next: Least Privilege Is an Operational Decision
The one-line version
A locally discovered service is a candidate endpoint, not an identity; enrollment must establish and bound trust before it creates durable authority.