session signing option are EVM-only. They do not grant authority to spend from the managed Solana wallet; see Solana availability.
Start with the shared embedded wallet setup, authenticate the user, and keep the returned session.accounts.evm.address as accountAddress. Configure the same sponsorship endpoints before granting or executing a session.
The examples below use the SDK’s viem ^2.55.0 peer dependency.
1
Create a session signer
Generate an ECDSA key for the session. Only send its public address to Rhinestone.The wallet signs with a viem
LocalAccount, here built from a locally accessible Hex private key. Keep the key in storage appropriate to its value and environment. A non-exportable KMS or HSM key needs a custom toAccount() signer, which this guide does not cover.2
Define the authority
Grant one ERC-20
transfer action on Base Sepolia. The recipient is fixed, each transfer is capped at 10 tokens, and that function can execute up to 25 times during the 24-hour window.definePermissions() derives the selector and calldata constraints from the ABI. The name and ABI make the review readable, but they are app-supplied metadata. The contract address, selector, parameter rules, validity window, and usage limit define the authority.See Session limits before granting broader actions or using assets from another chain.3
Ask the user to grant the session
Use the initialized The embedded wallet shows the scope, collects the owner’s passkey authorization, and installs or enables the session-key configuration. No target chain is selected implicitly.
wallet client and authenticated account from the embedded wallet setup:4
Persist the signer and handle
Store both halves before signing with the session. The signer is the capability; the handle describes the approved onchain configuration.The stable, account-scoped key remains available after the in-memory
grant result is gone. If an account has multiple grants, store a grant map and selected grantId under that account namespace instead of overwriting this record.sessionStorage survives a page refresh but not a tab close. Use encrypted application storage or a protected backend secret store when the session must last longer. Never send the private key to Rhinestone.Rhinestone separately stores public grant metadata so the handle can be recovered from the same account namespace. It cannot recover the private signer.5
Send with the session
Pass the stored handle and its signer as The wallet prepares the intent, rebuilds the per-chain session-key signatures from the handle, and submits them. It returns the same result as a passkey-signed send, and sponsorship works the same way. The onchain validator rejects calls outside the grant.Session signing supports EVM destinations only. It can request
session on sendIntent(). The wallet signs with the session key instead of the passkey, so no dialog or passkey prompt appears. The user must still be signed in to the account that granted the session.destination.token, with or without amount, funded from an explicit EVM source; a cross-chain source needs the grant installed there too. A recipient, Solana source or destination, or module install is refused. The signer must be the granted session key. With sendBatchIntent({ intents, session }), each intent is prepared, signed, and submitted independently, so check every entry of results.Try a scoped session
This testnet demo grants a narrower action than the transfer example above: mint 0.1 mUSD to your own account on Base Sepolia, up to 25 times within 24 hours. Grant the permission once, then mint without another passkey prompt. Fees are sponsored, and the session key stays in this tab’ssessionStorage.