Skip to main content
Treat sponsorship authority as permission to spend your organization’s money. Authenticate callers, validate every requested intent on the backend, and configure spend limits as a separate backstop.

Validate sponsorship requests

Filter grant issuance

createSponsorshipSigner({ shouldSponsor }) runs its filter before Rhinestone receives an extension token. For EVM, create the signer for the authenticated request, using the account address your application session is allowed to use:
The destination chain, account, and destination calls must all pass. Follow Set up to connect the signer to your token endpoints.This section describes the embedded-wallet SDK’s canonical input, not the raw Caucasus HTTP schema. createSponsorshipSigner() accepts a canonical draft or a prepared envelope containing intentInput, and normalizes it before running shouldSponsor.Use shouldSponsor.intent to validate the complete normalized input. Narrow on "contractVersion" in input before reading singular fields such as account.svm, source, destination, and options; legacy inputs use destinationChainId, account.address, and destinationExecutions. The current singular approval contract is sdk-3.0.0-caucasus; unknown or retired contracts are refused. See the migration guide for compatible versions.The individual chain, account, calls, and app-fee filters do not validate source assets, delivery amounts, recipients, or instruction data. Validate these through the full intent filter when they affect your policy.For each EVM extension-token request:
  1. Authenticate the caller with your normal application session.
  2. Resolve the smart account that your session is allowed to use.
  3. Validate policy fields outside the built-in filter against the complete intent payload.
  4. Configure the account filter with the resolved address.
  5. Check every destination target, function selector, calldata rule, and value limit your product requires.
  6. Return 403 without minting a token when any check fails.
verifyWalletAccount() from @rhinestone/wallet/server can confirm that an address is recognized by the embedded wallet provider. Your application session must still establish that the current user is allowed to use it.

Managed Solana issuance

For Solana-only setup and spends, chain and intent filters apply. The chain callback receives the destination ID: 792703809 for Solana mainnet and 792703810 for devnet. Presence of any EVM account, calls, or appFees filter rejects the input, even if that callback would return true. The EVM example above therefore does not allow Solana.Use an authenticated, VM-aware policy that binds account.svm and the intended Swig, cluster, and authority to the session. Compare base58 addresses exactly. Validate the full source, destination, options, and ordered instruction data; do not authorize arbitrary instructions from a program allowlist alone.The helper accepts Swig creation and authority additions only for secp256r1 passkeys with all or secp256k1 recovery keys with manageAuthority. Authority removal and other permissions are refused. Accepted shapes are not proof that an authority belongs to the user: your policy must check the exact key and purpose. Managed setup fees and rent are app-paid, without user fallback.See Solana setup and recovery and authority limits.

Current enforcement boundary

Rhinestone verifies that the JWT signing key belongs to the project, that access and extension token identity claims match, and that the extension token’s jti has not already been used. The extension token also carries the canonical intent digest.An issuance filter alone does not prevent a client from changing the payload afterward. The embedded wallet browser flow returns the extension token to the client, so use compatible client and server helpers that issue intent-scoped grants under the matching approval contract. Do not infer intent binding from JWT authentication or a version header alone.
CORS and cookie attributes only constrain compatible browsers. They do not stop a script from calling a public endpoint. Use them as browser hardening, not as authorization.

Key rotation and fallback

Rotate signing keys by registering a new kid, switching issuance, then disabling the old key after outstanding tokens expire.Do not switch a rejected sponsored transaction to user-paid at submission time. With embedded wallets, sponsorshipMode: "required" remains fail-closed; to fall back, send a new intent with "disabled" and an explicit source, which the user reviews before signing. This send fallback does not apply to managed Solana setup, which is app-paid only. See Sponsor fees before enabling fallback.

Configure budgets

Configure limits on the Dashboard’s Sponsorship screen.
Dashboard drawer for enabling and setting a monthly sponsorship usage limit in USD.

Set an organization-wide monthly usage limit in the Dashboard.

Unset limits are unlimited. Project caps do not divide or reserve the organization budget; every project draws from the same organization sponsorship account. The monthly limit does not reserve funds between concurrent intents, so simultaneous admissions can exceed it before their charges are recorded. Testnet sponsorship is not metered against these mainnet limits.
Request validation answers “should this intent be sponsored?” Budgets answer “can this sponsorship account pay for it?” Use both.

Failure behavior

Funding affects the quote and the operations the user authorizes. A user-paid fallback always needs a new quote and user approval. Managed Solana setup has no such fallback; restore sponsorship or leave setup unfinished.

Operational checklist

  • Keep private keys and API keys in backend secret storage.
  • Authenticate token-minting and transaction endpoints.
  • Bind every account to the authenticated application session.
  • Allowlist chains, contracts, functions, and values as narrowly as possible.
  • Set project per-intent caps and an organization monthly limit.
  • Log policy denials without logging tokens, private keys, or sensitive request data.