What you sign
The signed message is the current time in milliseconds as a decimal string (Date.now().toString()), signed with EIP-191
personal_sign. There is no separate challenge or login nonce — the timestamp is
the anti-replay token. The signer may be the wallet itself or a delegated
session key.
The three values — wallet, timestamp, signature — are the same on both
transports. WebSocket sends them as public/login params; HTTP sends them as
X-Derive* headers. The server reads each value from the header or the
request params interchangeably.
WebSocket
Open the socket, then callpublic/login with {wallet, timestamp, signature}.
The result is the array of subaccount IDs the connection is now authenticated
for (an empty session-key subaccount list resolves to all of the wallet’s current
subaccounts).
HTTP
REST requests authenticate per request — there is no separate login call. Attach the same three values as headers to each private request:X-DeriveWallet, X-DeriveTimestamp, X-DeriveSignature.
Who may sign the login
Thesignature may come from the wallet itself or from a
session key the wallet has delegated:
1
Direct-wallet auth
The recovered signer equals
wallet. The connection receives full
authority, and the timestamp freshness window is enforced — sign
immediately before connecting.2
Session-key auth
The recovered signer is a registered session-key address whose
wallet
matches and which is not expired. The key’s authority is bounded by its
access scopes, and if it declares an IP
whitelist the request IP must be on it. Freshness is not enforced on
this path.The exact timestamp validity window for direct-wallet auth is
deployment-specific; allow for it (and a little clock skew) when signing the
login timestamp.
Re-authentication
Long-lived WebSocket sessions periodically re-verify the stored login signature as part of the heartbeat, so a connection stays authenticated without a freshpublic/login. See Connecting over WebSocket for heartbeat and
reconnection guidance.