Aleph
Gateway RPC

Authentication

Gateway authentication flow, token management, and device pairing

The Gateway supports device-based authentication with HMAC-SHA256 signed tokens. When require_auth is enabled, every client must authenticate before issuing RPC calls.

Authentication Flow

Client connects via WebSocket
    |
    v
+-----------------------------+
| require_auth enabled?       |
|   Yes -> First frame must   |
|          be "connect"       |
|   No  -> Direct access      |
+-----------------------------+
    |
    v (if auth required)
+-----------------------------+
| Validate credentials        |
|   - Bearer token + HMAC sig |
|   - Device fingerprint      |
|   - Public key verification |
+-----------------------------+
    |
    v
+-----------------------------+
| Issue session token          |
| Assign client role           |
| (operator or node)           |
+-----------------------------+

When authentication is not required (local-only deployments), clients connect and begin issuing RPC calls immediately. When enabled, the very first WebSocket frame must be a connect request.

Connect Request

The connect method negotiates protocol version, identifies the client, and presents credentials.

Request:

{
  "jsonrpc": "2.0",
  "id": 1,
  "method": "connect",
  "params": {
    "minProtocol": 1,
    "maxProtocol": 1,
    "client": {
      "id": "macos-app",
      "version": "1.0.0",
      "platform": "macos"
    },
    "role": "operator",
    "auth": {
      "token": "bearer_token",
      "signature": "hmac_sha256_signature"
    }
  }
}

Response (success):

{
  "jsonrpc": "2.0",
  "id": 1,
  "result": {
    "session_token": "session-uuid",
    "role": "operator",
    "scopes": ["*"],
    "expires_at": 1706400000000
  }
}

Response (failure):

{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32001,
    "message": "Authentication failed: invalid token"
  }
}

Connect Parameters

ParameterTypeRequiredDescription
minProtocolnumberYesMinimum protocol version the client supports
maxProtocolnumberYesMaximum protocol version the client supports
client.idstringYesClient identifier (e.g. "cli", "macos-app", "web")
client.versionstringYesClient version string
client.platformstringYesPlatform ("macos", "ios", "android", "cli", "web")
rolestringYesRequested role: "operator" or "node"
auth.tokenstringYesBearer token issued during device pairing
auth.signaturestringYesHMAC-SHA256 signature of the token

Token Types

Aleph uses two categories of tokens, each serving a different phase of the authentication lifecycle.

Device Token

A long-lived token issued during device pairing. Stored securely on the client device (Keychain on macOS/iOS, encrypted storage on other platforms). Used to obtain session tokens via the connect method.

PropertyValue
LifetimeUntil revoked
StorageClient-side secure storage
ScopeDevice-level identity
RotationManual via auth.rotate

Session Token

A short-lived token issued by the Gateway after a successful connect handshake. Automatically included in subsequent requests during the WebSocket session. Expires after 24 hours by default.

PropertyValue
Lifetime24 hours (default)
StorageIn-memory (Gateway)
ScopePer-session
RotationAutomatic on reconnect

HMAC-SHA256 Signing

All tokens are signed with HMAC-SHA256. The Gateway never stores raw token values -- only their HMAC hashes are persisted in SQLite.

Token Issuance:
  token        = UUID v4
  signature    = HMAC-SHA256(secret, token)
  stored_hash  = HMAC-SHA256(secret, token)

Token Validation:
  1. Verify HMAC signature matches token
  2. Compute hash = HMAC-SHA256(secret, token)
  3. Look up hash in database
  4. Check expiry and revocation status
  5. Update last_used_at timestamp

The HMAC secret is generated at server startup (32 bytes of cryptographically secure random data). It can be persisted across restarts for token continuity.

Token Validation Result

When a token passes validation, the Gateway returns an internal TokenValidation containing the identity context for the session.

{
  "token_id": "tok-uuid",
  "device_id": "dev-uuid",
  "role": "operator",
  "scopes": ["*"],
  "remaining_ms": 86400000
}
FieldTypeDescription
token_idstringUnique token identifier
device_idstringDevice that owns this token
rolestring"operator" (full control) or "node" (limited)
scopesstring[]Permission scopes (["*"] = all)
remaining_msnumberMilliseconds until token expires

Device Roles

RoleDescriptionPermissions
operatorFull control (CLI, macOS App, Web UI)All RPC methods, tool execution, config changes
nodeLimited execution (iOS/Android nodes)Agent interaction, read-only config, no exec approval

Device Pairing

New devices must be paired before they can authenticate. The pairing flow uses a challenge-response protocol.

Pairing Flow

New Device                          Gateway
    |                                  |
    |--- auth.pairing.request -------->|
    |    { device_name, platform,      |
    |      public_key }                |
    |                                  |
    |<-- pairing_id, challenge --------|
    |                                  |
    |                    Owner approves via CLI/UI
    |                                  |
    |--- auth.pairing.complete ------->|
    |    { pairing_id, signed_challenge}|
    |                                  |
    |<-- device_token, signature ------|

Approve/Reject Pairing

The owner approves or rejects pending pairing requests via auth.pairing.approve or auth.pairing.reject.

Approve:

{
  "jsonrpc": "2.0",
  "id": 1,
  "method": "auth.pairing.approve",
  "params": {
    "pairing_id": "pair-uuid",
    "role": "operator",
    "scopes": ["*"]
  }
}

Reject:

{
  "jsonrpc": "2.0",
  "id": 2,
  "method": "auth.pairing.reject",
  "params": {
    "pairing_id": "pair-uuid",
    "reason": "Unknown device"
  }
}

List Devices

{
  "jsonrpc": "2.0",
  "id": 3,
  "method": "auth.devices.list"
}

Response:

{
  "jsonrpc": "2.0",
  "id": 3,
  "result": {
    "devices": [
      {
        "device_id": "dev-uuid-1",
        "device_name": "MacBook Pro",
        "device_type": "macos",
        "role": "operator",
        "scopes": ["*"],
        "last_seen_at": 1706400000000,
        "created_at": 1706313600000
      }
    ]
  }
}

Token Rotation

Tokens can be rotated without re-pairing. The old token is revoked and a new one is issued with the same permissions.

Request:

{
  "jsonrpc": "2.0",
  "id": 1,
  "method": "auth.rotate",
  "params": {
    "token": "old-token",
    "signature": "old-signature"
  }
}

Response:

{
  "jsonrpc": "2.0",
  "id": 1,
  "result": {
    "token": "new-token",
    "signature": "new-signature",
    "token_id": "new-tok-uuid",
    "expires_at": 1706486400000
  }
}

Token Revocation

Revoke a specific token or all tokens for a device.

Revoke single token:

{
  "jsonrpc": "2.0",
  "id": 1,
  "method": "auth.revoke",
  "params": {
    "token_id": "tok-uuid"
  }
}

Revoke all device tokens:

{
  "jsonrpc": "2.0",
  "id": 2,
  "method": "auth.revoke_device",
  "params": {
    "device_id": "dev-uuid"
  }
}

Guest Access

Aleph supports invitation-based guest access with scoped permissions. Guests receive limited access to specific tools.

Guest Invitation Flow

  1. Owner creates invitation with scoped permissions and optional expiry
  2. Guest activates invitation using the one-time token
  3. Gateway creates identity context with frozen permissions
  4. Guest operates within scope -- PolicyEngine enforces boundaries
{
  "jsonrpc": "2.0",
  "id": 1,
  "method": "auth.invite",
  "params": {
    "guest_name": "Mom",
    "allowed_tools": ["translate"],
    "expires_in_seconds": 86400,
    "display_name": "Mom"
  }
}

Response:

{
  "jsonrpc": "2.0",
  "id": 1,
  "result": {
    "invitation_token": "inv-token-uuid",
    "url": "https://aleph.local/join?t=inv-token-uuid",
    "expires_at": 1706486400000
  }
}

Permission Matching

Guest permissions use a hierarchical matching system:

PatternMatches
"translate"Exact tool name translate
"shell"Category match: shell:exec, shell:read, etc.
"*"Wildcard: all tools

Security Headers

When using the HTTP fallback endpoint, include authentication in headers:

HeaderValueDescription
AuthorizationBearer <token>Device or session token
X-Aleph-Signature<hmac_signature>HMAC-SHA256 of the token
X-Aleph-Device-Id<device_id>Device identifier

Error Codes

CodeConstantDescription
-32000AUTH_REQUIREDNo credentials provided
-32001AUTH_FAILEDInvalid token or signature
-32002PERMISSION_DENIEDValid auth but insufficient permissions

Configuration

{
  "gateway": {
    "require_auth": true,
    "token_expiry_ms": 86400000,  // 24 hours
    "max_devices": 10,
    "auto_cleanup_expired": true
  }
}

See Also

On this page