Invite payload reference¶
A WorkspaceInvitePayload is what travels from inviter to
recipient. Two on-wire representations of the same JSON:
- URL —
hive://invite/<base64url-of-payload> - Short code — hyphen-grouped base64url, no scheme prefix (so it pastes cleanly into chat/voice)
Schema¶
{
"workspaceID": "00000000-0000-0000-0000-000000000000",
"workspaceName": "Hive architecture pass",
"relayEndpoint": "https://rendezvous.example.com",
"relayTokenEnvVar": "HIVE_RELAY_TOKEN",
"relayAuthHint": "Set HIVE_RELAY_TOKEN in your shell before launching Hive.",
"inviterAccountID": "00000000-0000-0000-0000-000000000000",
"inviterDeviceID": "00000000-0000-0000-0000-000000000000",
"inviterDisplayName": "Alice",
"inviterSigningPublicKey": "<base64 32-byte Ed25519>",
"issuedAt": "2026-05-30T12:00:00Z",
"expiresAt": "2026-05-30T13:00:00Z",
"passcode": "rosebud"
}
| Field | Required | Notes |
|---|---|---|
workspaceID |
yes | UUID of the workspace to join |
workspaceName |
yes | Display label for the accept sheet |
relayEndpoint |
no | If present, recipient auto-configures transport.rendezvous.endpoint |
relayTokenEnvVar |
no | Env var the recipient should consult for bearer token |
relayAuthHint |
no | Human-readable note rendered in the accept sheet |
inviterAccountID |
yes | UUID, joins recipient's WorkspaceMember roster |
inviterDeviceID |
yes | UUID, used to look up signatures from the inviter's device |
inviterDisplayName |
yes | Shown in the accept sheet |
inviterSigningPublicKey |
yes | 32-byte Ed25519, raw bytes base64-encoded |
issuedAt |
yes | ISO-8601 |
expiresAt |
no | ISO-8601; recipient rejects if Date.now > expiresAt |
passcode |
no | Short string; recipient must paste it separately to accept |
URL encoding¶
The URL form is:
The payload-as-JSON is encoded with JSONEncoder.outputFormatting =
[.sortedKeys] + ISO-8601 dates, base64url-encoded (- for +,
_ for /, no = padding). Wrapped to be URL-safe; survives most
chat clients without further escaping.
Short code¶
Same bytes as the URL form, hyphenated every 4 characters:
The recipient can paste the URL OR the bare base64url OR the
hyphenated short code — WorkspaceInvitePayload(string:) accepts
all three.
Passcode handling¶
Passcodes are embedded in the payload's signed bytes. That means:
- An attacker who captures only the URL cannot verify the passcode without first decoding it — but they can decode it, since the payload is just signed not encrypted.
- The passcode's value lives in the same artifact as the rest of the payload.
That's why the recommendation is to share the passcode on a separate channel — if Alice DMs the URL on Slack and texts the passcode, an attacker would have to compromise both channels to redeem.
For high-stakes deployments, deliver the invite over a channel that's already authenticated end-to-end (Signal, age-encrypted file).
Validation rules¶
The recipient's Hive enforces:
isCurrentlyValid()—Date.now <= expiresAt(or no expiry).- If
passcodeis set, recipient must paste a matching string in the accept sheet. - Future envelopes signed by
inviterSigningPublicKeyverify against the embedded key.
What the recipient's Hive does not verify:
- Whether the inviter has the authority to invite — that's enforced workspace-side by the authz evaluator at envelope acceptance time.
- Whether the relay endpoint is reachable — pre-flighted lazily on first publish.
See hive-core (invite types) for the canonical
implementation.