Relay · Authentication
Authenticate Relay requests
The host authenticates its users and signs Relay tokens. Relay verifies the token and uses its claims to select the tenant and user. Relay does not provide a login flow.
Production flow
Relay admin creates tenant
→ host stores the host-sync credential
→ host fetches the tenant signing secret
→ host signs a short-lived user token
→ client uses the token with REST or WebSocket Tenant creation returns a tenant_id, host_sync_client_id, and host_sync_client_secret. Keep the host-sync credential on a trusted server. Never send it to a browser or mobile client.
The host fetches the active signing secret with HTTP Basic authentication:
POST /api/host/tenants/{tenant_id}/jwt_secret/fetch
Authorization: Basic base64(<host_sync_client_id>:<host_sync_client_secret>) A successful response contains the current kid, algorithm, issuer, audience, and jwt_secret_primary. The response is marked Cache-Control: no-store, private and Pragma: no-cache.
Token contract
Relay accepts an HS256 JWT with this protected header:
{
"alg": "HS256",
"typ": "JWT",
"kid": "019d4900-0000-7000-8000-000000000001"
} The payload requires iss, aud, exp, tenant_id, and user_id:
{
"iss": "tonetify-relay",
"aud": "tonetify-relay",
"exp": 1910000000,
"tenant_id": "019d4900-0000-7000-8000-000000000001",
"user_id": "019d4900-0000-7000-8000-000000000002"
} Relay enforces all of these conditions:
- The algorithm is HS256.
issandaudaretonetify-relay.exphas not passed.- The protected header contains
kid. kidequals the payload’stenant_id.- The tenant exists and is not disabled.
- The signature matches the tenant’s primary or previous active secret.
nbf is not part of the current validation contract.
Use the token
Every tenant REST request includes the token as a bearer credential:
Authorization: Bearer <jwt> WebSocket connections use the same token contract. The topic still includes the tenant and channel identifiers, but those values cannot override the signed tenant identity.
Failure behavior
An invalid or missing bearer token returns:
{ "errors": ["invalid_or_missing_token"] } An unknown tenant, incorrect host-sync client ID, or incorrect host-sync secret returns the same host-sync response:
401 Unauthorized { "errors": ["invalid_host_sync_credentials"] } Relay does not reveal whether a tenant or credential exists.
Rotation and revocation
Relay can keep a primary and an optional previous JWT secret for each tenant. During normal rotation, new tokens use the primary secret while existing short-lived tokens may continue to verify against the previous secret.
Use rotate followed by expire_previous for planned rotation. Use revoke_all for an incident. Disabling a tenant rejects both JWT verification and host-sync secret fetches.
Next: send a retry-safe message.