Human identity and machine binding โ€” draft

Status: Draft for joint review; not ratified or a published extension. This document proposes a custom resource-request profile. Do not advertise this path as an extension URI or infer production readiness from it.

The Workbench owner approved the custom signed-header direction for the Roblox first release on 2026-10-21. This selects the implementation direction, not ratification of the full profile or approval to provision production. The actual issuers, client claim and trust configuration remain unresolved.

Proposed request profile

The Workbench sends a machine OAuth access token as Authorization: Bearer and a separately signed, short-lived human JWT as X-Upperhand-Identity-Grant. Both travel server-to-server over HTTPS; neither belongs in browser storage, URLs, transcripts or logs.

The specialist verifies both signatures and operator-pinned trust before using claims. Proposed human claims are iss, sub, aud, iat, exp and azp:

Issuer, JWKS location, allowed algorithms, audience, scope and client-claim mapping are operator configuration, not trust learned from a token or card. The grant issuer signs only from an authenticated human session and an authorized client/target relationship. It does not sign arbitrary sub values supplied by the caller. The specialist checks machine and human entitlements on every protected operation, including task lookup and feedback. Missing identity fails closed; there is no production test-token or anonymous-user fallback.

This remains a bearer profile: a stolen token/grant pair can be replayed within its validity window. Client binding prevents using a grant with a different authenticated machine; it is not proof of possession or a single-use nonce scheme.

Not ID-JAG

The IETF Identity Assertion JWT Authorization Grant draft uses token exchange with an identity provider and resource authorization server to obtain an access token. A custom second JWT header on a resource request is not that flow. Adopting ID-JAG would be a separate design with its own issuer support and tests; this draft makes no ID-JAG conformance claim.

Roblox implementation evidence, 2026-10-21

The Roblox owner reports that src/auth.ts verifies pinned issuer/JWKS/audience, RS256 or ES256, machine sub/exp, bls:invoke, and human sub/iat/exp with a 10-minute maximum age and lifetime. It already accepts the proposed header.

It does not read azp or client_id from either token. Entitlements use (machine_sub, human_sub); persisted owner is SHA256(JSON.stringify([machineSub, humanSub])). Another entitled machine for the same human can present the same valid human grant today. Signature verification alone therefore does not satisfy the proposed client binding.

Client binding need not change ownership. The proposed implementation compares human azp against one operator-selected, issuer-documented machine client claim, rejecting absent, non-string, empty or mismatched values without fallback between claims. It retains machine sub, human sub, entitlement lookup and the existing owner hash unchanged. If the issuer establishes that sub identifies the client, that can be the selected claim; otherwise use its documented client claim separately.

Changing issuer or subjects can still require entitlement/history migration. Do not strand persisted tasks or silently broaden access. The owner confirmed the orb runs AUTH_MODE=local; machine issuer/JWKS, OAuth token URL, agent audience and human issuer/JWKS are unset. Local test-user authentication does not establish a production client mapping.

Workbench implementation evidence, 2026-10-21

The local Workbench implementation signs five-minute RS256 grants from authenticated Clerk sessions and operator-configured audience/client policy. It passes the human subject internally to the coordinator, outside request metadata. Direct and routed specialist calls use the same signing path. The configured RSA key's public half is served at /.well-known/jwks.json. Missing configuration fails closed; the private key never reaches the browser.

Signature, claim and public-key tests pass with disposable keys. Neither production trust nor Roblox's client-binding check is certified. The pilot publishes one key; overlapping-key rotation remains unimplemented.

Decisions and acceptance still required

  1. Provision the selected header profile's human grant issuer, specialist audiences, machine issuer and client registration after operator approval. Confirm the exact machine client claim and clock tolerance first.
  2. Validate the implemented session-to-target signing path with the real issuers and entitled humans. The local implementation is not evidence that production identity registration is complete.
  3. Agree migration of existing entitlements/history if identity keys change, and document revocation behavior within the bearer lifetime.
  4. Test missing/expired/wrong-audience grants, invalid signatures, unapproved issuers, absent scopes, and cross-human ownership. Critically, test two machines both entitled for one human: a grant bound to one must be rejected with the other's valid machine token.
  5. Exercise direct and coordinator-routed calls with the actual issuers before enabling the registry entry. Record evidence without credentials.