Skip to main content

Security Architecture

Cavos uses a non-custodial OAuth-based wallet architecture. Users authenticate with their existing identity providers (Google, Apple, Firebase) and Cavos derives a unique wallet address from their verified identity—without ever storing private keys on a server.

How It Works

Wallet Derivation

addressSeed   = Poseidon(user_sub, salt)
wallet_address = calculate_contract_address_from_hash(
  salt:                 addressSeed,
  class_hash:           cavosAccountClassHash,
  constructor_calldata: [addressSeed, jwksRegistryAddress],
  deployer_address:     0x0
)
ComponentDescription
user_subOAuth subject claim (unique per user per provider)
saltPer-app salt derived from your App ID
class_hash0x5426dc61fb0cbbe0a04ab63d926f321552ece71e2014c6a42faab493385e0a2
jwksRegistryAddressOn-chain JWKS registry holding RSA public keys
The wallet address is deterministic—same user + same app always produces the same wallet. No private key storage required.

Session Keys

Instead of storing master private keys, Cavos uses short-lived session keys:
  1. Session Creation: SDK generates a fresh ECDSA keypair on each login
  2. Nonce Binding: nonce = Poseidon(eph_pubkey_lo, eph_pubkey_hi, max_block, randomness) is embedded in the JWT before the OAuth redirect
  3. On-chain Registration: The smart contract verifies the JWT RSA signature and registers the session key
  4. Transaction Signing: All subsequent transactions are signed with the session key
┌─────────────┐     ┌───────────────┐     ┌──────────────┐
│ Google JWT  │ ──► │ Cavos Account │ ──► │ Session Key  │
│ (proof)     │     │ (verifies     │     │ (signs txs)  │
│             │     │  RSA-2048)    │     │              │
└─────────────┘     └───────────────┘     └──────────────┘

Session Expiration

ParameterDefaultDescription
sessionDuration~24 hoursBlocks until session expires
renewalGracePeriod~24 hoursWindow to renew before expiry
Sessions can be renewed with a fresh JWT before expiration.

Per-App Wallet Isolation

Each app registered on Cavos gets its own app salt, ensuring:
  • Same user on different apps = different wallet addresses
  • Apps cannot access each other’s user funds
  • Users maintain separate identities per app
// App A wallet for user@gmail.com
0x1234...abc

// App B wallet for user@gmail.com (same user, different wallet)
0x5678...def

What Cavos Stores vs Doesn’t Store

DataStored?Notes
Private keys❌ NeverDerived client-side only
OAuth tokens❌ NeverJWT verified and discarded
User sub (ID)✅ HashedFor MAU tracking only
Wallet address✅ PublicFor analytics

What Cavos Cannot Do

  • Access user funds: No private keys stored anywhere
  • Sign transactions: Only users with valid OAuth JWTs can sign
  • Impersonate users: JWTs are verified on-chain via JWKS registry

On-Chain Verification

The Cavos Account smart contract verifies every transaction:
  1. JWT Signature: RSA-2048 verification using Garaga v1.0.1+ (is_valid_rsa2048_sha256_signature, ~11.8M L2 gas). The RSA public key (stored as 24 × felt252 in 96-bit limbs) is fetched from the on-chain JWKS registry.
  2. Nonce Validation: Ensures Poseidon(eph_pubkey_lo, eph_pubkey_hi, max_block, randomness) in the JWT matches the registered session
  3. Expiration Check: JWT exp and session max_block must be within validity period
  4. Session Key: Ephemeral Stark key must match JWT-registered session
// Simplified verification flow
fn validate_transaction(jwt, session_sig) {
    let key = jwks_registry.get_key_if_valid(kid);   // 24×felt252 RSA2048Chunks
    is_valid_rsa2048_sha256_signature(jwt_bytes, key, hint);  // Garaga
    verify_nonce_matches(jwt.nonce, session.ephemeral_pub);
    verify_session_not_expired(session.max_block);
    verify_ecdsa_signature(session_sig, session.ephemeral_pub);
}

JWKS Registry & Argus

RSA public keys are managed by two complementary on-chain contracts:
  • JWKSRegistry: Stores active RSA-2048 keys (24 × felt252 per key in Garaga RSA2048Chunks format)
  • Argus (trustless JWKS v2): Permissionless key registration via Reclaim zkFetch proofs. Accepts keys only from hardcoded Google, Apple, and Firebase JWKS endpoints—no admin required and no mutable whitelist.
NetworkJWKSRegistryArgus
Sepolia0x0112c6a8a69e4d9a2e74b4638e1495d69266de9f6f796727d4a52a7ab0a48db20x07cd8487786091e4a2c1841cad4e16b815d61a068383c2a2b15dcb2415f1d767
Mainnet0x076ff6853197538b4d4c925b2c775014fae9b5c14f63262b13f2e49f732e21f70x00cbcd49655919c0628fd7d999f8aadcb167a0450a75f9dfffef8ad8175f1de4

Attack Vectors & Mitigations

OAuth Provider Compromise

If Google/Apple’s signing keys are compromised:
  • Risk: Attacker could forge JWTs
  • Mitigation: JWKS registry on-chain. Old keys can be deactivated; Argus enables permissionless rotation when providers publish new keys.
  • Mitigation: Session bound to a specific client-side-generated session key via the nonce

Browser XSS

If attacker injects JavaScript:
  • Risk: Could access session key in session storage
  • Mitigation: Session keys are short-lived (~24h)
  • Mitigation: Session bound to specific JWT claims
  • Mitigation: Implement Content Security Policy

Backend Compromise

If Cavos servers are compromised:
  • Risk: Attacker could return malicious app_salt
  • Mitigation: app_salt is deterministic from app_id—users would notice different wallet
  • Mitigation: No private keys stored to steal

Man-in-the-Middle

  • Mitigation: All API calls over HTTPS
  • Mitigation: JWT signature verification is on-chain (cannot be spoofed)

Best Practices

For Developers

  1. Use HTTPS everywhere
  2. Implement Content Security Policy to prevent XSS
  3. Validate all user inputs before contract calls
  4. Don’t expose appId secrets in client-side code (appId is public, but don’t commit env files)
  5. Monitor your MAU usage via dashboard

For Users

  1. Protect your OAuth account (Google/Apple) with 2FA
  2. Review connected sessions periodically
  3. Use on trusted devices only
  4. Check transaction details before signing

Compliance Notes

Cavos wallet infrastructure is:
AspectStatus
Non-custodial✅ Users control their own wallets
No key storage✅ Private keys never stored server-side
User-initiated only✅ All transactions require active user auth
Auditable✅ All verification logic is on-chain
This documentation describes the OAuth-based wallet architecture. Cavos does not hold custody of any user funds.