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
)
| Component | Description |
|---|
user_sub | OAuth subject claim (unique per user per provider) |
salt | Per-app salt derived from your App ID |
class_hash | 0x5426dc61fb0cbbe0a04ab63d926f321552ece71e2014c6a42faab493385e0a2 |
jwksRegistryAddress | On-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:
- Session Creation: SDK generates a fresh ECDSA keypair on each login
- Nonce Binding:
nonce = Poseidon(eph_pubkey_lo, eph_pubkey_hi, max_block, randomness) is embedded in the JWT before the OAuth redirect
- On-chain Registration: The smart contract verifies the JWT RSA signature and registers the session key
- 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
| Parameter | Default | Description |
|---|
sessionDuration | ~24 hours | Blocks until session expires |
renewalGracePeriod | ~24 hours | Window 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
| Data | Stored? | Notes |
|---|
| Private keys | ❌ Never | Derived client-side only |
| OAuth tokens | ❌ Never | JWT verified and discarded |
| User sub (ID) | ✅ Hashed | For MAU tracking only |
| Wallet address | ✅ Public | For 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:
- 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.
- Nonce Validation: Ensures
Poseidon(eph_pubkey_lo, eph_pubkey_hi, max_block, randomness) in the JWT matches the registered session
- Expiration Check: JWT
exp and session max_block must be within validity period
- 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.
| Network | JWKSRegistry | Argus |
|---|
| Sepolia | 0x0112c6a8a69e4d9a2e74b4638e1495d69266de9f6f796727d4a52a7ab0a48db2 | 0x07cd8487786091e4a2c1841cad4e16b815d61a068383c2a2b15dcb2415f1d767 |
| Mainnet | 0x076ff6853197538b4d4c925b2c775014fae9b5c14f63262b13f2e49f732e21f7 | 0x00cbcd49655919c0628fd7d999f8aadcb167a0450a75f9dfffef8ad8175f1de4 |
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
- Use HTTPS everywhere
- Implement Content Security Policy to prevent XSS
- Validate all user inputs before contract calls
- Don’t expose appId secrets in client-side code (appId is public, but don’t commit env files)
- Monitor your MAU usage via dashboard
For Users
- Protect your OAuth account (Google/Apple) with 2FA
- Review connected sessions periodically
- Use on trusted devices only
- Check transaction details before signing
Compliance Notes
Cavos wallet infrastructure is:
| Aspect | Status |
|---|
| 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.