Skip to content
Prividium

Per-User RPC and Transaction Authorizations

What it is (Overview)

Prividium™ exposes a Per-User RPC endpoint that embeds a user-scoped token in the RPC URL. This enables wallets to call JSON-RPC without attaching a bearer JWT on every request, while still enforcing user-level authorization and transaction constraints through the Permissions API.

A transaction authorization is a single-use, short-lived capability: the user pre-authorizes one specific transaction (exact wallet, recipient, nonce, calldata, and value) for a limited time, so the wallet can submit exactly that transaction and nothing else.

  • The Per-User RPC endpoint is POST at: /rpc/wallet/{token} (served by the Prividium™ api)
  • The token is issued by the Permissions API and stored per user
  • Prividium™ api validates the token and enforces transaction authorizations before delegating to the target RPC

End-to-end sequence of a transaction using the Per-User RPC URL

Loading diagram...

Token lifecycle

  1. Issue or fetch user's token (auth required):
    • GET /api/wallet/personal-rpc-token
    • If none exists, one is generated and stored on the user record
  2. Rotate/Invalidate token (auth required):
    • POST /api/wallet/invalidate
    • Generates and stores a new token; previous token becomes invalid

Token format: 16 hex characters (64 bits of entropy) generated via randomBytes(8).toString('hex').

Wallet RPC behavior (mocked and filtered)

For privacy and policy enforcement, the wallet RPC route restricts and/or mocks certain methods:

  • eth_getBlockByNumber: returns a real block number, while other block fields are mocked and the transactions list is always empty.
  • eth_getBlockByHash: returns a mocked block with an empty transactions list. It does not reveal transaction hashes.
  • eth_getTransactionReceipt: returns a receipt only for the transaction hash stored on the active authorization. It returns null for any other hash. Before the target RPC reports a mined receipt, it can also return null for the stored hash.
  • eth_getCode: returns '0x' for the authorized wallet address (EOA), and a dummy code for any other address (treated as contracts).
  • eth_getTransactionCount: returns the real nonce only for the authorized wallet address. Returns a forbidden error for any other address.
  • Many other methods are forbidden to avoid data leakage and side‑channel discovery (e.g., eth_estimateGas, eth_call, logs/filters, etc.).

Transaction authorizations

Transaction authorizations restrict what a token can do on-chain for a limited time window.

  • Authorize a transaction (auth required):
    • POST /api/wallet/transaction-authorization
    • Body includes: walletAddress, toAddress, nonce, calldata, value
    • Send the exact transaction value. Use 0 when the transaction sends no ETH.
    • Active for 1 hour from creation
    • Purpose: pre‑authorizes a single transaction shape for a short window, binding the user's wallet, target contract, nonce, calldata, and value. Required before submitting the signed transaction via the Per-User RPC URL.

Wallet RPC handlers in the Proxy enforce transaction authorizations. For example, balance queries are allowed only for the wallet address in the authorization, and raw transactions are checked against the enabled from, to, nonce, calldata, and value.

Authorization flow (step-by-step)

  1. Authorize: client (with user auth) calls api POST /api/wallet/transaction-authorization with walletAddress, toAddress, nonce, calldata, value. Send 0 when the transaction sends no ETH. The Permissions API stores a transaction authorization active for 1 hour.
  2. Submit tx: dapp calls api POST /rpc/wallet/{token} with eth_sendRawTransaction.
    • Prividium™ api decodes tx to from, to, nonce, calldata, value and checks exact match against the latest active authorization.
  3. On success: Prividium™ api forwards to target RPC and stores the resulting transactionHash on the authorization.
  4. Post‑tx reads:
    • eth_getBlockByHash stays mocked and returns an empty transactions list.
    • eth_getTransactionReceipt accepts only the transaction hash stored on the active authorization. It returns null for any other hash. It can also return null until the target RPC exposes a mined receipt for that hash.
  5. Expiry: When activeUntil passes or no authorization exists, wallet RPC calls become unauthorized or return empty results depending on the method.

Using it (SDK and User Panel)

  • Prividium™ SDK: getWalletToken() and getWalletRpcUrl() helpers
    • getWalletRpcUrl() derives ${PERMISSION_API_URL}/rpc/wallet/{token} from the configured API base URL
  • User Panel: Fetches token and offers "Add Network to Wallet", passing the ${PERMISSION_API_URL}/rpc/wallet/{token} as the RPC URL to the wallet

Enabling via configuration

  • Disabled by default: the per-user wallet RPC routes are not exposed unless explicitly enabled.
  • How to enable:
    • Set the Prividium™ API configuration flag to true (environment variable WALLETS_API_ENABLED=true).
    • When enabled, the Prividium™ API registers:
      • POST /rpc/wallet/{token} (wallet RPC endpoint)
      • Wallet token and authorization routes under /api/wallet/*

Security considerations

  • Token is a bearer secret. Treat it like a password in URLs (rotate if leaked).
  • 64-bit entropy (16 hex chars). Use HTTPS to prevent interception.
  • Tokens do not expire automatically; rotation replaces the previous token.
  • Transaction authorizations significantly limit what can be performed via the tokenized RPC by binding specific walletAddress, toAddress, nonce, calldata, and value, and by time window.