Both paths resolve, at the guard, to a workspace-scoped principal. From
there, every authorization check is “is this principal entitled to act
on this resource?” —
workspaceId is the answer in both cases.
API keys
sessions:read, wallet:read, etc.) — see
API keys.
What gets attached to the request:
workspaceId
parameter must match the key’s bound workspace.
Wallet sessions (dashboard)
The dashboard signs in by proving control of a wallet, then picking which workspace to act as.HttpOnly, SameSite=Lax. Signature verification on every
request happens in constant time.
Signature support: EOAs via ECDSA recovery, and ERC-1271 smart contract
wallets via isValidSignature (Coinbase Smart Wallet, Safe, etc.) —
viem handles both transparently against a Base RPC. The verifying
chain is configurable (Base mainnet in prod, Base Sepolia in early
access).
What gets attached to the request:
/me and
/workspaces) reject sessions still in the wallet-only state with
INVALID_INPUT: workspaceNotSelected.
Authorization
Two layers:(workspaceId, role) is the cached result.
SpiceDB’s responsibility is narrow: it models the wallet → workspace
membership graph. Session-level authorization (consumer/operator) is
a direct FK match on consumer_workspace_id / operator_workspace_id
against the principal’s workspaceId.
Workspace creation has no auth
/me — who am I
Rotation + revocation
API keys: see API keys. Mint new, revoke old, the revoked key keeps working for 60s while your fleet rolls. Wallet sessions: expire after 12h. To rotate sooner, sign in again. There’s no server-side revocation list — leaked cookies remain valid until the TTL elapses. Production-grade revocation can come later if the threat model demands it.Logging
keyId + workspaceId on every API-key call. walletAddress + workspaceId
on every wallet-session call. Plaintext API keys and signatures are
never logged.