# ByteBind Protocol **Status:** Draft **Version:** 0.7 (editorial revision) **Copyright:** © 2026 Bytes & Coffee Digital Studio This revision changes the presentation of draft 0.7. Transcript labels, field encodings, profiles, transport requirements, and state transitions are unchanged. Section numbers are retained for references from the implementation and tests. ## 1. Overview ByteBind authorizes management access to a public application through a fresh exchange involving an authorized device on a private overlay network. The browser receives a challenge from the application, completes an attestation request on the private network, and returns a redemption proof. The application redeems that proof with the Authority before issuing a lease or executing a protected request. The session profile grants a short management lease renewed through further attestation. The transaction-bound profile binds authorization to one stored application request. Network departure stops successful renewals; an existing lease remains valid until its server-side deadline. ## 2. Design goals - Keep the application's management interface on its public HTTPS origin. - Require a fresh exchange through an explicitly authorized private device. - Bind the public and private exchanges through cryptographic proofs. - Consume transactions once and scope grants to the application and policy. - Release only the identity claims required by the application. The browser can complete the exchange in the background when network access and browser permissions allow it. ## 3. Trust assumptions and limits The Authority, registered RP, overlay identity service, and authorized device are trusted for their assigned roles. The mechanism establishes device-backed participation; human presence or approval requires a separate user-authentication step. Applications requiring it SHOULD layer an appropriate mechanism such as WebAuthn onto the exchange. The challenge and attestation secrets are transferable. Their possession does not uniquely identify a browser process or prevent deliberate relay by an authorized participant. A copied application session cookie remains usable while its server-side lease is valid. Compromise of an authorized device is outside this threat model. ## 4. Parties and state ownership | Party | Responsibility | |---|---| | Client | Browser code that obtains a challenge, calls the private attestation endpoint, and returns a proof | | Relying Party (RP) | Public application that creates transactions, redeems proofs, and enforces its own sessions and operations | | Authority | Service that owns transactions, authenticates RPs, identifies private peers, evaluates policy, and issues grants | | Attestation provider | Authority component mapping a private connection to authenticated overlay identity and policy claims | The Authority MUST own all ByteBind transaction state. The RP MUST access that state only through the private control channel in section 5.2, including when both processes run on the same host. Their databases and transaction state MUST remain separate. The RP maintains its own browser-attempt bindings, leases, and stored application requests. ## 5. Channels ### 5.1 Browser ↔ RP Public HTTPS carries the initial access request, challenge response, completed proof, and application response. The RP validates its browser origin and manages its own cookies and request authorization. ### 5.2 RP ↔ Authority control channel The control channel MUST be authenticated and confidential. This profile defines two supported transports: - **HTTPS between overlay nodes:** both endpoints MUST be on the private overlay, and the connection MUST remain on that overlay. - **Unix domain socket on a shared macOS, Linux, or BSD host:** the socket MUST be in a directory writable only by the Authority account. Access MUST be limited to the Authority and registered RPs. Section 16.3 specifies RP authentication for each transport. ### 5.3 Browser ↔ Authority The browser calls the private HTTPS attestation endpoint directly. The Authority maps the accepted connection to overlay identity and returns the encrypted attestation response on that connection. ## 6. Threat model In-scope attackers include internet clients, unauthorized overlay peers, shared-in nodes, malicious pages opened on authorized devices, and clients attempting message forgery, replay, concurrent redemption, or DNS rebinding. The checks in sections 11 and 20 restrict which origins can use an authorized device's private connection for a transaction. Authority policy distinguishes allowed devices from other peers that can reach the endpoint. Atomic state transitions enforce one-time use under concurrent requests. ## 7. Protocol values Unless otherwise noted, byte values are encoded in JSON as unpadded base64url. | Value | Size | Generated by | Purpose | |---|---:|---|---| | `cid` | 16 bytes | ByteBind Authority | Opaque challenge identifier | | `C` | 32 bytes | ByteBind Authority | Public-channel challenge secret | | `S` | 32 bytes | ByteBind Authority | Attestation/redeem secret | | `N` | 32 bytes | Client | Client freshness nonce | | `IP` | 16 bytes | ByteBind Authority | Attested peer address in IPv6 form; IPv4 uses IPv4-mapped IPv6 | | `IV` | 12 bytes | ByteBind Authority | AES-GCM nonce | All random values MUST be generated using a cryptographically secure random number generator. Each challenge MUST be single-use. ### 7.1 JSON field names JSON members are case-sensitive and normative. Protocol values use the names in the table above, exactly: `cid`, `C`, `N`, `H1`, `H2`, `R`. Endpoints MUST reject a body with a missing member, an unknown member, a value that is not unpadded canonical base64url, or a value of the wrong decoded length. --- ## 8. Domain separation Every cryptographic transcript MUST begin with a protocol/version-specific label. ByteBind version 1 uses exactly these labels, encoded as ASCII bytes. The session profile uses: ```text bytebind/v1/h1 bytebind/v1/h2 bytebind/v1/redeem ``` The transaction-bound profile (section 9.2) uses: ```text bytebind/v1/tx/request bytebind/v1/tx/h1 bytebind/v1/tx/h2 bytebind/v1/tx/redeem ``` Transcripts using any other labels are not ByteBind version 1. In particular, the `tailbind/v1/*` labels of drafts 0.1 to 0.5 (when the protocol was named TailBind) and the earlier `bd-mgmt/v1/*` labels belong to predecessor drafts and MUST NOT be accepted by a ByteBind v1 implementation. Implementations MUST NOT reuse a label for a different transcript meaning. All concatenated transcript fields have fixed lengths in version 1, except inside the request digest `Q`, whose variable-length fields are length-prefixed (section 9.2). Any future variable-length field MUST likewise use an unambiguous encoding such as length-prefixing or a canonical serialization. --- ## 9. HTTP exchanges The protocol consists of five request/response pairs. RP authentication paths are application-defined. Authority paths below are those used by the reference implementation; deployments MUST preserve the specified payload and checks. | Caller → receiver | Request | Response | Sections | |---|---|---|---| | Browser → RP | POST to access-request endpoint | Challenge: `cid`, `C`, `authority` | 10 | | RP → Authority | POST `/v1/begin` over control channel | RP-scoped transaction material | 10 | | Browser → Authority | POST `/attest` with `cid`, `N`, `H1` | Encrypted `H2` | 11–12 | | Browser → RP | POST to proof-submission endpoint with `cid`, `R` | Session state or operation result | 13 | | RP → Authority | POST `/v1/redeem` over control channel | Scoped grant | 13 | The RP calls the control endpoints while handling the corresponding browser request. It returns the final application response only after successful redemption and local authorization. Requests use ordinary HTTP POST. ### 9.1 Processing order 1. The browser requests a lease or submits a protected operation to the RP. 2. The RP creates a transaction with the Authority and returns its challenge. 3. The browser submits its initial proof directly to the private Authority. 4. The Authority authorizes the device and returns the encrypted secret. 5. The browser submits a redemption proof to the RP. 6. The RP redeems it with the Authority and applies the resulting grant. ### 9.2 Application request binding (transaction-bound profile) ByteBind has two profiles: the **session profile** (section 9.3) and the **transaction-bound profile** described here. They use different transcript labels, so a transcript always identifies its profile and one can never be accepted as the other. In the transaction-bound profile, the privileged application request is submitted in the initial access request and bound to the ByteBind transaction by a 32-byte request digest `Q`: ```text Q = SHA-256( "bytebind/v1/tx/request" || len(method) || method || len(target) || target || len(headers) || headers || len(body) || body ) ``` `len(x)` is the byte length of `x` as an unsigned 64-bit big-endian integer. `method` is the uppercase ASCII method, `target` the path and query as sent, `headers` the profile-selected headers serialized as `name:value` lines (name lowercased, surrounding whitespace trimmed from name and value) sorted by code point and joined by `\n`, and `body` the body bytes. An implementation profile MAY narrow which headers are covered but MUST NOT change this encoding. The Client MUST compute `Q` from its submitted request and MUST NOT substitute an RP-supplied digest. The transaction-bound profile uses its own labels: ```text bytebind/v1/tx/h1 bytebind/v1/tx/h2 bytebind/v1/tx/redeem ``` and these transcripts: ```text H1 = HMAC-SHA256(key = C, data = "bytebind/v1/tx/h1" || cid || N || Q) K = HKDF-SHA256(ikm = C, salt = H1, info = "bytebind/v1/tx/h2", length = 32) AAD = "bytebind/v1/tx/h2" || cid || N || H1 R = HMAC-SHA256(key = S, data = "bytebind/v1/tx/redeem" || cid || C || IP || Q) ``` All other cryptographic steps are as in sections 11 to 13. The RP MUST send `Q` to the Authority in the transaction-creation request, and the Authority MUST store it with the transaction and verify `H1` and `R` against it. The RP MUST also store the request itself (or enough to execute it) under the transaction's `cid`, MUST execute only that stored request, and MUST execute it at most once. Redemption consumes the proof. The grant covers the request, audience, policy, and claims stored with the transaction. The RP MUST NOT execute the request before receiving a valid grant. After receiving the grant, the RP executes the stored request and returns the actual application result in the application response. ### 9.3 Session profile The session profile is an optimization built on the same ceremony. In the session profile, the initial request asks for creation or renewal of a management lease. The session profile has no `Q` and uses the `bytebind/v1/h1`, `bytebind/v1/h2`, and `bytebind/v1/redeem` transcripts of sections 11 to 13 exactly. Redemption consumes the proof and returns a grant for the scoped lease. The RP returns the application response after creating or renewing that lease. The transaction-bound profile provides stronger per-operation authorization, while the session profile reduces repeated ceremony overhead for lower-risk management operations. ## 10. Access requests and transaction creation ### 10.1 Initial access request and control transaction The Client submits an access request to the RP. Before executing a protected operation or issuing a lease, the RP creates a transaction through the authenticated private control channel. The transaction-creation request SHOULD identify: ```text rp_id audience allowed_origin requested_policy transaction_ttl optional application context Q (transaction-bound profile only) ``` The reference control endpoint is: ```http POST /v1/begin Content-Type: application/json {"audience":"manage","profile":"session"} ``` For the transaction-bound profile, use `"profile":"tx"` and include `Q` as base64url. The authenticated RP's registration supplies origin and policy. Registration controls which requested values the Authority accepts. The Authority generates: ```text cid = random(16) C = random(32) S = random(32) ``` The Authority MUST validate `allowed_origin` against the requesting RP's registration rather than accept whatever origin the RP asks for. One RP MUST NOT be able to obtain an auth set bound to another RP's origin. The Authority then stores authoritative transaction state including: ```text cid C S rp_id audience allowed_origin requested_policy Q (transaction-bound profile only) status = pending challenge_expires_at ``` The Authority returns an **auth set** split by audience. A typical split is: ```text RP-visible: cid C authority endpoint expires_in (seconds until the attestation window closes) opaque authority handle or verifier Client-visible: cid C authority endpoint ``` Expiry is opaque to the Client (section 15.2): the client-visible portion carries no expiry. Times on the control channel are relative durations, never absolute timestamps, so each host enforces durations on its own clock. The RP SHOULD receive only the material it needs to continue and later redeem the transaction. Private-network identity, device tags, peer metadata, and the secret `S` SHOULD remain Authority-side unless a specific deployment requires otherwise. ### 10.2 Challenge response and RP attempt binding The Authority returns the RP-scoped transaction material. The RP forwards the browser portion as its challenge response: ```json { "cid": "", "C": "", "authority": "https://authority.example.ts.net:8443" } ``` `authority` is the Authority's base URL; the client sends the attestation request to `/attest`. The challenge response MUST NOT carry the attestation window's expiry: the Authority enforces it, and the Client either completes in time or fails. The RP MUST refuse an access request whose `Origin` header is not its own public origin, so a malicious website cannot start an authentication attempt in the user's browser. The access request arrives unauthenticated, yet it makes the RP store a pending request and call the Authority. The RP MUST bound the size of an access request body and the number of pending transactions it holds, and the Authority MUST bound pending transactions per RP, so an internet client cannot use access requests to exhaust either party. The RP MAY additionally issue a short-lived state cookie binding the browser to this RP-side authentication attempt. Recommended cookie properties: ```text HttpOnly Secure SameSite=Strict Path= short expiry ``` If such a cookie is used, the RP SHOULD store only its hash. ## 11. POST /attest — request validation The client generates: ```text N = random(32) ``` It computes: ```text H1 = HMAC-SHA256( key = C, data = "bytebind/v1/h1" || cid || N ) ``` The client sends to the private ByteBind Authority: ```http POST /attest Content-Type: application/json Origin: https://public.example { "cid": "", "N": "", "H1": "" } ``` The browser MUST communicate with the ByteBind Authority directly. The private peer address MUST be obtained from the accepted socket. Forwarded-address headers MUST NOT be trusted. ### 11.1 Required checks The ByteBind Authority MUST check, in order: 1. `Origin` exactly matches the origin of some registered RP, and `Host` exactly matches the expected private attestation host. Requests failing either check MUST be refused without reading or changing any transaction state. 2. `Content-Type` is `application/json`. This forces a CORS preflight; the Authority MUST refuse the "simple" content types (`text/plain`, `application/x-www-form-urlencoded`, `multipart/form-data`) that a page could send without one. 3. `cid` exists, is `pending`, and is inside its attestation window. 4. `Origin` exactly matches the `allowed_origin` stored with that `cid`. Matching *some* registered origin is not enough: otherwise a page on RP A's origin could attest a challenge an attacker obtained from RP B, read `H2` (CORS permits A's origin), open it with the attacker's `C`, and redeem it at RP B. 5. `H1` is valid using constant-time comparison. 6. The socket peer address belongs to the supported private-network address space. 7. The attestation provider identifies the peer as a valid node. 8. Authority policy authorizes that node. 9. The challenge transitions atomically from `pending` to `attested`. A failure at check 3 or later MUST burn the challenge, but only from the state the request expected (`pending`), so a request that lost a race never burns the winner's newer state. ### 11.2 Atomicity The transition MUST be concurrency-safe. Each transition is a single conditional update that must change exactly one row. That update is the concurrency protection; no transaction is held across the authorization step. Holding a write lock while waiting on the attestation provider would block every other writer. A typical SQL pattern is: ```sql -- 1. Read, without a write lock. SELECT C, S, allowed_origin FROM challenges WHERE cid = ? AND status = 'pending' AND challenge_expires_at > :now; -- 2. Verify Origin, H1, and the peer with the attestation provider. -- 3. Transition; require exactly one changed row. UPDATE challenges SET status = 'attested', attested_ip = ?, attested_peer_id = ?, attested_at = :now, redeem_expires_at = :now + :redeem_window WHERE cid = ? AND status = 'pending' AND challenge_expires_at > :now; ``` If zero rows are updated, attestation fails: another request won, or the window closed. Burns and transitions MUST be durable before the response is sent. An implementation that wraps them in a transaction MUST commit it on failure paths too; rolling back a burn when the handler raises an error silently re-arms the challenge. ## 12. Attestation response After device authorization succeeds, the ByteBind Authority returns a response that only a holder of `C` can open. ### 12.1 Key derivation Derive: ```text K = HKDF-SHA256( ikm = C, salt = H1, info = "bytebind/v1/h2", length = 32 ) ``` ### 12.2 Plaintext ```text P = IP || S ``` `IP` is the peer address observed by the ByteBind Authority and stored with the challenge. ### 12.3 Authenticated encryption Generate: ```text IV = random(12) ``` Define associated data: ```text AAD = "bytebind/v1/h2" || cid || N || H1 ``` Encrypt using AES-256-GCM: ```text E = AES-256-GCM( key = K, iv = IV, plaintext = P, aad = AAD ) ``` The transmitted `E` includes the GCM authentication tag. The response is: ```text H2 = IV || E ``` and is returned as: ```json { "H2": "" } ``` ### 12.4 Client processing The client: 1. derives `K`; 2. parses `IV` and `E`; 3. decrypts and authenticates using the exact `AAD`; 4. rejects the response if authentication fails; 5. extracts `IP` and `S`. ## 13. Proof submission and redemption The Client submits its completed proof to the RP. The RP MUST wait for a valid Authority grant before executing a protected request or issuing a lease. The Client computes: ```text R = HMAC-SHA256( key = S, data = "bytebind/v1/redeem" || cid || C || IP ) ``` The transaction-bound profile uses the transcript in section 9.2, which additionally binds `Q`. The Client submits the proof to the RP (the path is RP-defined): ```http POST /bytebind/v1/affirm Content-Type: application/json { "cid": "", "R": "" } ``` If the RP set a state cookie with the challenge response, that cookie is included automatically. The RP MUST refuse a proof submission whose `Origin` header is not its own public origin, and MUST check the state cookie before continuing. The Client MUST NOT submit an independently chosen `IP` value during redemption. ### 13.1 Control redemption request After receiving a validly formed proof submission, the RP sends a redemption request to the Authority over the authenticated private control channel. Conceptually: ```http POST /v1/redeem { "cid": "", "R": "", "audience": "..." } ``` The Authority verifies: 1. `cid` exists. 2. The transaction belongs to the requesting RP and audience. 3. Transaction state is exactly `attested`. 4. The transaction is inside its redeem window, which starts at attestation (section 15.1). 5. `R` matches the expected HMAC using the Authority's stored `S`, `C`, and `attested_ip`, plus `Q` in the transaction-bound profile. 6. The transaction atomically transitions from `attested` to `redeemed`, changing exactly one row. A failure at check 3 or later MUST burn the transaction from the `attested` state. A successfully redeemed transaction MUST NOT be redeemable again. ### 13.2 Grant response Successful redemption returns the Authority's grant. It MUST be scoped to the RP, audience, policy, and transaction bound during creation. Example: ```json { "active": true, "expires_in": 180, "claims": { "device_id": "node-abc123", "authorization": ["manage:read"] } } ``` The exact claims returned are policy-controlled. The Authority SHOULD disclose only what the RP needs. For example, an RP that only needs a yes/no authorization decision need not receive tailnet username, node tags, peer IP, or other private-network metadata. The RP MUST validate the grant before applying its authorization. The grant's `expires_in` is the number of seconds, counted from when the RP receives the grant, for which the Authority's authorization holds. The RP measures it on its own clock. Any session lease or other authority the RP derives from a grant MUST NOT outlast it; the RP MAY end it sooner. The grant MUST NOT carry absolute expiry timestamps. ### 13.3 Application response Only after receiving a valid grant MAY the RP exercise the granted authority. For the transaction-bound profile, the RP executes the stored request bound to the redeemed `cid`, at most once, and returns the actual application result in its application response. For the session profile, the RP MAY create or renew the short-lived scoped session lease authorized by the grant, then return the resulting application response. The RP remains responsible for its own: - session cookie; - CSRF protection; - application authorization beyond the Authority's grant; - local logout; - session expiry; - idempotency and at-most-once execution of transaction-bound operations. ## 14. Challenge state machine ```text pending ──attestation──▶ attested ──redemption──▶ redeemed │ │ └── qualifying failure ─┴──▶ burned ``` - `pending`, `attested`, `redeemed`, and `burned` are the only states. `redeemed` and `burned` are terminal. - Expiry is a time comparison against the stored deadlines, not a state. A transaction past its deadline is treated as dead and removed by cleanup. - Every transition is a conditional update from one expected state that MUST change exactly one row. - A failed check burns the transaction only from the state that request expected, so a request that lost a race never burns the winner's newer state. --- ## 15. Session leases and re-attestation ByteBind works especially well with short-lived sessions and silent renewal. The intended user experience is continuous and ambient: while an authorized management page remains open, the browser MAY repeat ByteBind in the background without prompting the user. A management session SHOULD be treated as a lease. ### 15.1 Recommended timing | Window | Recommended | Purpose | |---|---|---| | Attestation window (transaction response to attestation request) | 30 seconds | A challenge must be attested promptly | | Redemption window | 10 seconds, starting at attestation | Bounds delay between attestation and redemption | | Session lease after the last successful ceremony | 180 seconds, at most 5 minutes | Bounds access after the device leaves | | Silent renewal interval | 60 seconds, fixed | Several renewals can fail before the lease ends | Implementations MAY choose shorter windows. Longer ones weaken the liveness guarantee and SHOULD be justified. Because Clients renew on a fixed interval, a session lease MUST be at least 90 seconds, so one failed renewal does not end it. The RP MUST enforce the lease deadline server-side against the last successful ceremony. Cookie retention does not determine authorization lifetime. The lease MUST NOT outlast the `expires_in` of the grant that created or renewed it, measured on the RP's clock (section 13.2). Each successful renewal SHOULD rotate the session token. ### 15.2 Expiry is opaque to the Client The RP and Authority enforce expiry on their own clocks. This profile keeps expiry fields out of browser responses and renews on a fixed interval. - The challenge response MUST NOT carry an expiry (section 10.2). - The application response in the session profile MUST NOT disclose the lease's expiry or remaining time. - The RP SHOULD issue the session cookie without `Max-Age` or `Expires` derived from the lease (for example as a browser-session cookie), so the cookie itself does not reveal the lease. - The Client renews on a fixed 60-second interval while the page is open. A refused protected request (for example HTTP 401) indicates that access is unavailable. A failed renewal leaves the existing lease subject to its stored deadline. Example: ```text successful ByteBind ceremony | v session valid: at most 5 min | +---- successful silent refresh ----> extend lease | +---- refresh fails ----------------> expire naturally ``` The page MAY repeat the ceremony silently while open. If the device: - leaves the private network; - loses the required tag; - is removed from the authorization policy; - becomes unreachable on the private channel; then re-attestation stops succeeding and the application session expires within at most one session TTL. The server SHOULD NOT indefinitely extend a session based solely on earlier authentication. --- ## 16. Tailscale attestation profile ByteBind core is provider-independent. The Tailscale profile maps private-network attestation to Tailscale identity. ### 16.1 Authority placement The ByteBind Authority MAY run independently of any relying application. It SHOULD be reachable: - from registered RPs over the private control channel: HTTPS between tailnet nodes, or a Unix domain socket when the RP runs on the same host (section 5.2); and - from client devices over a browser-facing tailnet attestation endpoint. ### 16.2 Browser-facing transport The Authority SHOULD: - bind directly to a Tailscale IP or otherwise preserve authenticated peer identity; - use HTTPS with a certificate valid for its `.ts.net` hostname (MUST for browser deployments: a page loaded over public HTTPS cannot call a plain-HTTP private address); - trust the socket source address rather than forwarded headers; - keep the attestation endpoint narrowly scoped. ### 16.3 RP-facing control transport The Authority MUST authenticate each RP independently, according to the transport (section 5.2): - **HTTPS between tailnet nodes:** the Authority MUST identify the RP from the authenticated overlay identity of the connecting node (Tailscale node identity, checked against ACL or tag policy), and MAY additionally require mTLS or a dedicated per-RP credential. The RP MUST verify the Authority's certificate for its `.ts.net` name. - **Unix domain socket:** the Authority MUST identify the RP from the kernel-reported peer credentials of the connecting process (`SO_PEERCRED` on Linux, `getpeereid` or `LOCAL_PEERCRED` on macOS and BSD) and map that user ID to a registered RP. Socket permissions provide an additional access restriction. The Authority MUST bind each auth set to the RP that requested it so another RP cannot redeem it. ### 16.4 Identity The Tailscale attestation provider SHOULD obtain identity from Tailscale's local control interface. A production implementation SHOULD prefer the Tailscale LocalAPI over shelling out to CLI commands where practical. Authority checks MAY include: - whether the peer is known to Tailscale; - whether it belongs to the expected tailnet; - whether it is a shared-in node; - stable node ID; - node tags; - user/account identity; - additional operator policy. ### 16.5 Authorization example ```text required tags: tag:bytebind-admin shared nodes: denied optional node allowlist: node-id-1 node-id-2 ``` The successful browser request itself provides the liveness signal. Tailscale identity and metadata determine whether that live peer is authorized. ## 17. Attestation provider interface A generalized implementation may define an interface similar to: ```python class AttestationProvider(Protocol): async def attest(self, request) -> "PeerAttestation": ... @dataclass class PeerAttestation: peer_id: str address: ipaddress.IPv6Address claims: dict[str, object] ``` The protocol core SHOULD depend only on the normalized attestation result rather than Tailscale-specific fields. This permits future providers for other authenticated private overlays. --- ## 18. Device-bound IdP profile A ByteBind Authority MAY also act as, or back, an OpenID Connect identity provider. In this profile the Authority converts successful device-backed liveness into a conventional application identity assertion. A typical flow becomes: ```text Browser | v OIDC authorization request | v ByteBind transaction | +---- public RP/browser path | +---- private browser/Authority path | v successful device attestation | v authorization code | v ID token / access token ``` Possible token claims include: ```json { "sub": "device:node-abc123", "device_id": "node-abc123", "auth_time": 1790981250, "amr": ["bytebind"], "acr": "urn:bytebind:device-bound" } ``` If the provider exposes a reliable human account mapping, the IdP MAY use a human identity for `sub` while carrying device identity separately. Applications MUST NOT assume that device identity alone proves which human is physically present. The key architectural property remains the same: **private-network participation occurs during authentication.** ## 19. Authority trust and selective disclosure The ByteBind Authority is a policy enforcement point and privacy boundary. It may know substantially more about a device than any individual RP should receive. For example: ```text Authority may know: private-network peer IP stable node ID tailnet identity human account mapping device tags shared-node status device posture requested RP complete ByteBind transaction state RP may receive: active = true attested_at authorization = manage:read optional pseudonymous device identifier ``` An RP SHOULD request the minimum claims required for its authorization decision. The Authority SHOULD enforce per-RP claim release policy rather than allowing the RP to arbitrarily query raw private-network identity. This permits ByteBind to act as a bridge from private-network trust into public application sessions without making every relying application a privileged observer of the private network. --- ## 20. Browser security requirements ### 20.1 CORS The private ByteBind Authority MUST use an explicit allowed public origin. Example: ```http Access-Control-Allow-Origin: https://manage.example.com Access-Control-Allow-Methods: POST Access-Control-Allow-Headers: Content-Type ``` Wildcard origin authorization MUST NOT be used. ### 20.2 Origin validation RP-side validation of the `Origin` header is mandatory for browser deployments. Page JavaScript cannot set an arbitrary `Origin` header for a cross-origin request. ### 20.3 Host validation The private service MUST validate its expected `Host`. This helps resist DNS rebinding and accidental exposure through alternate hostnames. ### 20.4 Content type The attestation endpoint MUST accept only `Content-Type: application/json` and MUST answer preflights only for `POST` with the `Content-Type` request header, from allowed origins. See section 11.1, check 2. ### 20.5 Private Network Access Browser requirements for public-to-private requests depend on the browser version. Where a supported browser sends `Access-Control-Request-Private-Network: true`, the Authority SHOULD answer allowed preflights with `Access-Control-Allow-Private-Network: true`. Deployments need to test local-network permissions and prompts on their supported browsers; this remains an open verification item. ### 20.6 RP origin validation The RP's access request and proof submission endpoints MUST validate the `Origin` header against the RP's own public origin (sections 10.2 and 13). ### 20.7 Browser crypto Web implementations SHOULD use WebCrypto for: - CSPRNG; - HMAC-SHA256; - HKDF-SHA256; - AES-GCM. --- ## 21. Replay resistance ByteBind uses several overlapping replay defenses: - random `cid`; - random `C`; - random client nonce `N`; - short challenge lifetime; - single-use challenge state; - transcript-bound HMACs; - AES-GCM associated data; - atomic state transitions; - short-lived application sessions. Recorded `H1`, `H2`, or `R` values are not valid for a fresh challenge. --- ## 22. Failure behavior Implementations SHOULD fail closed. On any of the following: - malformed input; - invalid base64url; - incorrect field length; - invalid `Origin`; - invalid `Host`; - unknown challenge; - expired challenge; - invalid HMAC; - decryption failure; - unauthorized device; - invalid state transition; - replay attempt; the server SHOULD return a generic authentication failure and SHOULD avoid exposing unnecessary authorization details. Failures burn the challenge as sections 11.1, 13.1, and 14 require. Rate limiting SHOULD cover the RP access and proof endpoints, the private attestation endpoint, and both control endpoints. Apply the body-size and pending-transaction limits in section 10.2 as well. --- ## 23. Storage considerations Challenge records contain ephemeral authentication secrets. Recommended protections: - store only for the minimum required lifetime; - delete or securely expire redeemed challenges quickly; - store only hashes of challenge-state cookies; - limit database access to the Authority process; RPs never access it directly (section 4); - avoid logging `C`, `S`, decrypted `H2`, state cookies, or session cookies; - use transaction boundaries for every state transition. --- ## 24. Reference database fields A minimal challenge table might contain: ```text cid C S state_cookie_hash rp_id allowed_origin status created_at challenge_expires_at attested_at attested_ip attested_peer_id attested_claims redeem_expires_at redeemed_at ``` `status` MUST be constrained to `pending`, `attested`, `redeemed`, and `burned`. --- ## 25. Authorization scope A successful grant applies to the registered RP, audience, policy, and transaction stored by the Authority. The RP remains responsible for application resource permissions and the execution of protected operations. ## 26. Proof continuity The initial proof establishes possession of `C` on a private connection accepted by the provider. Opening `H2` releases `S` for that transcript. The redemption MAC establishes possession of `S`, and the Authority consumes the transaction. These guarantees depend on the trusted participants described in section 3. Session freshness is bounded by the server-side lease in section 15. ## 27. Terminology This document uses transaction creation, challenge response, attestation, proof submission, redemption, and grant to describe the HTTP exchanges. Existing implementation method names remain compatible with earlier drafts. ## 28. Example implementation layout One possible Python packaging model: ```text bytebind-core bytebind-tailscale bytebind-fastapi bytebind-flask bytebind-django ``` or: ```bash pip install "bytebind[tailscale,fastapi]" ``` The protocol specification SHOULD remain independent of any particular framework or implementation language. --- ## 29. Test vectors A production-quality protocol release SHOULD publish machine-readable test vectors covering: - H1 computation, for both profiles; - the transaction-bound request digest `Q`, including length-prefix edge cases; - HKDF output; - AES-GCM H2 construction; - H2 decryption; - redeem HMAC; - malformed inputs; - expired challenges; - replayed challenges; - concurrent attestation; - concurrent redemption. Recommended file: ```text test-vectors/bytebind-v1.json ``` This allows independent implementations in Python, Go, Rust, JavaScript, or other languages to verify interoperability. --- ## 30. Versioning Protocol versions MUST be cryptographically domain-separated. Version changes that alter: - field encoding; - transcript structure; - key derivation; - encryption; - challenge semantics; - attestation semantics; MUST use a new protocol version label. Implementations MUST NOT silently reinterpret a version 1 transcript under a later version. --- ## 31. IANA / standards status ByteBind is a draft application protocol with no IETF standards status. Drafts 0.1 to 0.5 called the protocol TailBind. It was renamed in draft 0.6 because the protocol does not depend on Tailscale (section 16 is one attestation profile among possible others). --- ## 32. License and attribution This specification text is: **© 2026 Bytes & Coffee Digital Studio** The name **ByteBind** is an open name. It is not a trademark, and anyone may use it to refer to an implementation of this protocol, conforming or not, without permission. An implementation SHOULD say which draft version it implements and SHOULD NOT claim conformance it does not have. A separate software license SHOULD govern reference implementations. Tailscale is a third-party product and trademark. ByteBind compatibility with Tailscale does not imply endorsement by Tailscale Inc.